<!DOCTYPE html>
<html lang="zh-CN">





<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/myblog/img/apple-touch-icon.png">
  <link rel="icon" type="image/png" href="/myblog/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="TakCode Blog">
  <meta name="author" content="谢芃">
  <meta name="keywords" content="">
  <title>JavaScript高级&amp;ES6 学习笔记 - TakCode</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/font-awesome/5.12.1/css/all.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/css/bootstrap.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/mdbootstrap/4.13.0/css/mdb.min.css" />
<link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/3.0.1/github-markdown.min.css" />

<link rel="stylesheet" href="//at.alicdn.com/t/font_1067060_qzomjdt8bmp.css">



  <link  rel="stylesheet" href="/myblog/lib/prettify/tomorrow-night-eighties.min.css" />

<link  rel="stylesheet" href="/myblog/css/main.css" />


  <link defer rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />


<!-- 自定义样式保持在最底部 -->


<meta name="generator" content="Hexo 4.2.0"></head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/myblog/">&nbsp;<strong>TakCode</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/">首页</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/archives/">归档</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/categories/">分类</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/tags/">标签</a>
          </li>
        
          
          
          
          
          <li class="nav-item">
            <a class="nav-link" href="/myblog/about/">关于</a>
          </li>
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="view intro-2" id="background" parallax=true
         style="background: url('/myblog/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask rgba-black-light flex-center">
          <div class="container text-center white-text fadeInUp">
            <span class="h2" id="subtitle">
              
            </span>

            
              
                <p class="mt-3 post-meta">
                  <i class="fas fa-calendar-alt" aria-hidden="true"></i>
                  星期一, 四月 15日 2019, 11:28 晚上
                </p>
              

              <p class="mt-1">
                
                  
                  <span class="post-meta">
                    <i class="far fa-chart-bar"></i>
                    16.1k 字
                  </span>
                

                
                  
                  <span class="post-meta">
                      <i class="far fa-clock"></i>
                      67 分钟
                  </span>
                

                
              </p>
            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5 z-depth-3" id="board">
          <div class="post-content mx-auto" id="post">
            
            <div class="markdown-body">
              <p>JavaScript高级&amp;ES6 学习笔记</p>
<a id="more"></a>

<h2 id="面向过程与面向对象"><a href="#面向过程与面向对象" class="headerlink" title="面向过程与面向对象"></a>面向过程与面向对象</h2><h3 id="面向过程POP"><a href="#面向过程POP" class="headerlink" title="面向过程POP"></a>面向过程POP</h3><ul>
<li>面向过程就是分析出解决问题所需要的步骤，然后用函数把这些步骤一步一步实现，使用的时候再一个一个的依次调用就可以了。</li>
</ul>
<h3 id="面向对象OOP"><a href="#面向对象OOP" class="headerlink" title="面向对象OOP"></a>面向对象OOP</h3><ul>
<li>面向对象是把事务分解成为一个个对象，然后由对象之间分工与合作。</li>
</ul>
<h3 id="面向过程与面向对象对比"><a href="#面向过程与面向对象对比" class="headerlink" title="面向过程与面向对象对比"></a>面向过程与面向对象对比</h3><table>
<thead>
<tr>
<th></th>
<th>面向过程</th>
<th>面向对象</th>
</tr>
</thead>
<tbody><tr>
<td>优点</td>
<td>性能比面向对象高，适合跟硬件联系很紧密的东西，例如单片机就采用的面向过程编程。</td>
<td>易维护、易复用、易扩展，由于面向对象有封装、继承、多态性的特性，可以设计出低耦合的系统，使系统 更加灵活、更加易于维护</td>
</tr>
<tr>
<td>缺点</td>
<td>不易维护、不易复用、不易扩展</td>
<td>性能比面向过程低</td>
</tr>
</tbody></table>
<h2 id="ES6中的对象与类"><a href="#ES6中的对象与类" class="headerlink" title="ES6中的对象与类"></a>ES6中的对象与类</h2><h3 id="对象"><a href="#对象" class="headerlink" title="对象"></a>对象</h3><p>对象是由属性和方法组成的：是一个无序键值对的集合,指的是一个具体的事物</p>
<ul>
<li>属性：事物的特征，在对象中用属性来表示</li>
<li>方法：事物的行为，在对象中用方法来表示 </li>
</ul>
<h4 id="创建对象"><a href="#创建对象" class="headerlink" title="创建对象"></a>创建对象</h4><pre><code class="js">//以下代码是对对象的复习
//字面量创建对象
var ldh = {
    name: &#39;刘德华&#39;,
    age: 18
}
console.log(ldh); // {name:&quot;刘德华&quot;,age:18}
//构造函数创建对象
  function Star(name, age) {
    this.name = name;
    this.age = age;
 }
var ldh = new Star(&#39;刘德华&#39;, 18)//实例化对象
console.log(ldh); // Star {name:&quot;刘德华&quot;,age:18}</code></pre>
<h3 id="类"><a href="#类" class="headerlink" title="类"></a>类</h3><ul>
<li>在 ES6 中新增加了类的概念，可以使用 class 关键字声明一个类，之后以这个类来实例化对象。类抽象了对象的公共部分，它泛指某一大类（class）对象特指某一个，通过类实例化一个具体的对象。</li>
<li>类的本质也是个函数function</li>
</ul>
<h4 id="创建类"><a href="#创建类" class="headerlink" title="创建类"></a>创建类</h4><p>示例</p>
<pre><code class="js">// 1. 创建类 class  创建一个 明星类
class Star {
    // 类的共有属性放到 constructor 里面
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
}
// 2. 利用类创建对象 new
var ldh = new Star(&#39;刘德华&#39;, 18);
console.log(ldh);// Star {name:&quot;刘德华&quot;,age:18}</code></pre>
<p>通过结果我们可以看出,运行结果和使用构造函数方式一样</p>
<h4 id="类创建添加属性和方法"><a href="#类创建添加属性和方法" class="headerlink" title="类创建添加属性和方法"></a>类创建添加属性和方法</h4><pre><code class="js"> // 1. 创建类 class
class Star {
    // 类的共有属性放到constructor里面， constructor是 构造器或者构造函数
    constructor(uname, age) {
      this.uname = uname;
      this.age = age;
      this.sing(this.uname); // 可以调用方法
    }//注意,方法与方法之间不需要添加逗号
    sing(song) {
      console.log(this.uname + &#39;唱&#39; + song);
    }
}
// 2. 利用类创建对象 new
var ldh = new Star(&#39;刘德华&#39;, 18);
console.log(ldh); // Star {uname: &quot;刘德华&quot;, age: 18}
ldh.sing(&#39;冰雨&#39;); // 刘德华唱冰雨</code></pre>
<p><strong>注意:</strong></p>
<ol>
<li>通过 class 关键字创建类, 类名我们还是习惯性定义首字母大写</li>
<li>类里面有个 constructor 函数,可以接受传递过来的参数,同时返回实例对象</li>
<li>constructor 函数 只要 new 生成实例时,就会自动调用这个函数, 如果我们不写这个函数,类也会自动生成这个函数</li>
<li>多个函数方法之间不需要添加逗号分隔</li>
<li>生成实例 new 不能省略</li>
<li>语法规范, 创建类 类名后面不要加小括号,生成实例 类名后面加小括号, 构造函数不需要加 function</li>
</ol>
<h4 id="类的继承"><a href="#类的继承" class="headerlink" title="类的继承"></a>类的继承</h4><p>示例</p>
<pre><code class="js">class Father {
    constructor(surname) {
        this.surname= surname;
    }
    say() {
        console.log(&#39;你的姓是&#39; + this.surname);
    }
}

class Son extends Father{  // 子类就继承了父类的属性和方法
}
var damao= new Son(&#39;刘&#39;);
damao.say();      //你的姓是刘</code></pre>
<ul>
<li><p>子类使用super关键字访问父类的方法</p>
<pre><code class="js">//定义了父类
class Father {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sum() {
        console.log(this.x + this.y);
    }
}
//子元素继承父类
class Son extends Father {
    constructor(x, y) {
        super(x, y); //使用super调用了父类中的构造函数
    }
    twoSum(){
        super.sum();
        super.sum();
    }
}
var son = new Son(1, 2);
son.sum(); //结果为3
son.twoSum(); // 打印两次</code></pre>
<pre><code></code></pre></li>
</ul>
<p><strong>注意:</strong> </p>
<ol>
<li><p>继承中,如果实例化子类输出一个方法,先看子类有没有这个方法,如果有就先执行子类的</p>
<ol start="2">
<li><p>继承中,如果子类里面没有,就去查找父类有没有这个方法,如果有,就执行父类的这个方法(就近原则)</p>
</li>
<li><p>如果子类想要继承父类的方法,同时在自己内部扩展自己的方法,利用super 调用父类的构造函数,super 必须在子类this之前调用</p>
<pre><code class="js">// 父类有加法方法
class Father {
   constructor(x, y) {
       this.x = x;
       this.y = y;
   }
   sum() {
       console.log(this.x + this.y);
   }
}
// 子类继承父类加法方法 同时 扩展减法方法
class Son extends Father {
 constructor(x, y) {
       // 利用super 调用父类的构造函数 super 必须在子类this之前调用,放到this之后会报错
       super(x, y);
       this.x = x;
       this.y = y;
}
   subtract() {
       console.log(this.x - this.y);
   }
}
var son = new Son(5, 3);
son.subtract(); //2
son.sum();//8</code></pre>
</li>
</ol>
</li>
<li><p>时刻注意this的指向问题,类里面的共有的属性和方法一定要加this使用.</p>
<ol>
<li><p>constructor中的this指向的是new出来的实例对象 </p>
</li>
<li><p>自定义的方法,一般也指向的new出来的实例对象</p>
<ol start="3">
<li>绑定事件之后this指向的就是触发事件的事件源</li>
</ol>
</li>
</ol>
</li>
<li><p>在 ES6 中类没有变量提升，所以必须先定义类，才能通过类实例化对象</p>
</li>
</ol>
<pre><code class="js">// 应该先定义类，再创建实例对象
class Star {
    constructor(uname, age) {
        this.uname = uname
        this.age = age
    }
}
// 创建实例对象
var ldh = new Star(&#39;刘德华&#39;，22)
console.log(ldh)</code></pre>
<h2 id="面向对象版tab-栏切换"><a href="#面向对象版tab-栏切换" class="headerlink" title="面向对象版tab 栏切换"></a>面向对象版tab 栏切换</h2><h3 id="功能需求"><a href="#功能需求" class="headerlink" title="功能需求"></a>功能需求</h3><ol>
<li>点击 tab栏,可以切换效果.</li>
<li>点击 + 号, 可以添加 tab 项和内容项.</li>
<li>点击 x 号, 可以删除当前的tab项和内容项.</li>
<li>双击tab项文字或者内容项文字可以修改里面的文字内容</li>
</ol>
<h3 id="案例准备"><a href="#案例准备" class="headerlink" title="案例准备"></a>案例准备</h3><ol>
<li><p>获取到标题元素</p>
</li>
<li><p>获取到内容元素</p>
</li>
<li><p>获取到删除的小按钮 x号</p>
</li>
<li><p>新建js文件,定义类,添加需要的属性方法(切换,删除,增加,修改)</p>
</li>
<li><p>时刻注意this的指向问题</p>
<pre><code class="html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;meta charset=&quot;utf-8&quot;&gt;
        &lt;title&gt;&lt;/title&gt;
        &lt;style type=&quot;text/css&quot;&gt;
            * {
                margin: 0;
                padding: 0;
            }

            ul li {
                list-style: none;
            }

            main {
                width: 960px;
                height: 500px;
                border-radius: 10px;
                margin: 50px auto;
            }

            main h4 {
                height: 100px;
                line-height: 100px;
                text-align: center;
            }

            .tabsbox {
                width: 900px;
                margin: 0 auto;
                height: 400px;
                border: 1px solid lightsalmon;
                position: relative;
            }

            nav ul {
                overflow: hidden;
            }

            nav ul li {
                float: left;
                width: 100px;
                height: 50px;
                line-height: 50px;
                text-align: center;
                border-right: 1px solid #ccc;
                position: relative;
            }

            nav ul li.liactive {
                border-bottom: 2px solid #fff;
                z-index: 9;
            }

            #tab input {
                width: 80%;
                height: 60%;
            }

            nav ul li span:last-child {
                position: absolute;
                user-select: none;
                font-size: 20px;
                top: -18px;
                right: 0;
                display: inline-block;
                height: 20px;
            }

            .tabadd {
                position: absolute;
                /* width: 100px; */
                top: 0;
                right: 0;
            }

            .tabadd span {
                display: block;
                width: 20px;
                height: 20px;
                line-height: 20px;
                text-align: center;
                border: 1px solid #ccc;
                float: right;
                margin: 10px;
                user-select: none;
            }

            .tabscon {
                width: 100%;
                height: 300px;
                position: absolute;
                padding: 30px;
                top: 50px;
                left: 0px;
                box-sizing: border-box;
                border-top: 1px solid #ccc;
            }

            .tabscon section,
            .tabscon section.conactive {
                display: none;
                width: 100%;
                height: 100%;
            }

            .tabscon section.conactive {
                display: block;
            }
        &lt;/style&gt;
    &lt;/head&gt;

    &lt;body&gt;
        &lt;main&gt;
            &lt;h4&gt;
                JS面向对象 动态添加标签页
            &lt;/h4&gt;
            &lt;div class=&quot;tabsbox&quot; id=&quot;tab&quot;&gt;
                &lt;!-- tab标签 --&gt;
                &lt;nav class=&quot;fisrstnav&quot;&gt;
                    &lt;ul&gt;
                        &lt;li class=&quot;liactive&quot;&gt;
                            &lt;span&gt;测试1&lt;/span&gt;
                            &lt;span class=&quot;guanbi&quot;&gt;x&lt;/span&gt;
                        &lt;/li&gt;
                        &lt;li &gt;
                            &lt;span&gt;测试2&lt;/span&gt;
                            &lt;span class=&quot;guanbi&quot;&gt;x&lt;/span&gt;
                        &lt;/li&gt;
                        &lt;li &gt;
                            &lt;span&gt;测试3&lt;/span&gt;
                            &lt;span class=&quot;guanbi&quot;&gt;x&lt;/span&gt;
                        &lt;/li&gt;
                    &lt;/ul&gt;
                    &lt;div class=&quot;tabadd&quot;&gt;
                        &lt;span&gt;+&lt;/span&gt;
                    &lt;/div&gt;
                &lt;/nav&gt;
                &lt;!-- tab 内容 --&gt;
                &lt;div class=&quot;tabscon&quot;&gt;
                    &lt;section class=&quot;conactive&quot;&gt;测试1&lt;/section&gt;
                    &lt;section&gt;测试2&lt;/section&gt;
                    &lt;section&gt;测试3&lt;/section&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/main&gt;
        &lt;script src=&quot;tab.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;</code></pre>
</li>
</ol>
<h3 id="切换"><a href="#切换" class="headerlink" title="切换"></a>切换</h3><ul>
<li><p>为获取到的标题绑定点击事件,展示对应的内容区域,存储对应的索引</p>
<pre><code class="js"> this.lis[i].index = i;
 this.lis[i].onclick = this.toggleTab;</code></pre>
</li>
<li><p>使用排他,实现只有一个元素的显示</p>
<pre><code class="js"> toggleTab() {
   //将所有的标题与内容类样式全部移除
     for (var i = 0; i &lt; this.lis.length; i++) {
     this.lis[i].className = &#39;&#39;;
     this.sections[i].className = &#39;&#39;;
     }
   //为当前的标题添加激活样式
     this.className = &#39;liactive&#39;;
    //为当前的内容添加激活样式
     that.sections[this.index].className = &#39;conactive&#39;;
  }</code></pre>
</li>
</ul>
<h3 id="添加"><a href="#添加" class="headerlink" title="添加"></a>添加</h3><ul>
<li><p>为添加按钮+ 绑定点击事件 </p>
<pre><code class="js"> this.add.onclick = this.addTab;</code></pre>
</li>
<li><p>实现标题与内容的添加,做好排他处理</p>
<pre><code class="js">addTab() {
    that.clearClass();
    // (1) 创建li元素和section元素 
    var random = Math.random();
    var li = &#39;&lt;li class=&quot;liactive&quot;&gt;&lt;span&gt;新选项卡&lt;/span&gt;&lt;span class=&quot;iconfont icon-guanbi&quot;&gt;&lt;/span&gt;&lt;/li&gt;&#39;;
    var section = &#39;&lt;section class=&quot;conactive&quot;&gt;测试 &#39; + random + &#39;&lt;/section&gt;&#39;;
    // (2) 把这两个元素追加到对应的父元素里面
    that.ul.insertAdjacentHTML(&#39;beforeend&#39;, li); // beforeend表示插入元素内部的最后一个子节点之后
    that.fsection.insertAdjacentHTML(&#39;beforeend&#39;, section);
    that.init();
}</code></pre>
</li>
</ul>
<h3 id="删除"><a href="#删除" class="headerlink" title="删除"></a>删除</h3><ul>
<li><p>为元素的删除按钮x绑定点击事件</p>
<pre><code class="js"> this.remove[i].onclick = this.removeTab;</code></pre>
</li>
<li><p>获取到点击的删除按钮的所在的父元素的所有,删除对应的标题与内容</p>
<pre><code class="js"> removeTab(e) {
     e.stopPropagation(); // 阻止冒泡 防止触发li 的切换点击事件
     var index = this.parentNode.index;
     console.log(index);
     // 根据索引号删除对应的li 和section   remove()方法可以直接删除指定的元素
     that.lis[index].remove();
     that.sections[index].remove();
     that.init();
     // 当我们删除的不是选中状态的li 的时候,原来的选中状态li保持不变
     if (document.querySelector(&#39;.liactive&#39;)) return;
     // 当我们删除了选中状态的这个li 的时候, 让它的前一个li 处于选定状态
     index--;
     // 手动调用我们的点击事件  不需要鼠标触发
     that.lis[index] &amp;&amp; that.lis[index].click();
 }</code></pre>
</li>
</ul>
<h3 id="编辑"><a href="#编辑" class="headerlink" title="编辑"></a>编辑</h3><ul>
<li><p>为元素(标题与内容)绑定双击事件</p>
<pre><code class="js"> this.spans[i].ondblclick = this.editTab;
 this.sections[i].ondblclick = this.editTab;</code></pre>
</li>
<li><p>在双击事件处理文本选中状态,修改内部DOM节点,实现新旧value值的传递</p>
<pre><code class="js">editTab() {
    var str = this.innerHTML;
    // 双击禁止选定文字
    window.getSelection ? window.getSelection().removeAllRanges() :                     document.selection.empty();
    // alert(11);
      this.innerHTML = &#39;&lt;input type=&quot;text&quot; /&gt;&#39;;
      var input = this.children[0];
      input.value = str;
      input.select(); // 文本框里面的文字处于选定状态
      // 当我们离开文本框就把文本框里面的值给span 
      input.onblur = function() {
      this.parentNode.innerHTML = this.value;
      };
      // 按下回车也可以把文本框里面的值给span
      input.onkeyup = function(e) {
      if (e.keyCode === 13) {
      // 手动调用表单失去焦点事件  不需要鼠标离开操作
      this.blur();
      }
    }
}</code></pre>
<pre><code class="js">完整代码
var that;
class Tab {
    constructor(id) {
        //获取元素
        that = this;
        this.main = document.querySelector(id);
        this.lis = this.main.querySelectorAll(&#39;li&#39;);
        this.sections = this.main.querySelectorAll(&#39;section&#39;);
        this.add = this.main.querySelector(&#39;.tabadd&#39;);
        this.ul = this.main.querySelector(&#39;.fisrstnav ul:first-child&#39;);
        this.fsection = this.main.querySelector(&#39;.tabscon&#39;);
        this.init();
    }
    init() {
        this.updateNode();
        //init 初始化操作让相关的元素绑定事件
        this.add.onclick = this.addTab;
        for (var i = 0; i &lt; this.lis.length; i++) {
            this.lis[i].index = i;
            this.lis[i].onclick = this.toggleTab;
            this.remove[i].onclick = this.removeTab;
            this.spans[i].ondblclick = this.editTab;
            this.sections[i].ondblclick = this.editTab;
        }
    }
    updateNode() {
        this.lis = this.main.querySelectorAll(&#39;li&#39;);
        this.sections = this.main.querySelectorAll(&#39;section&#39;);
        this.remove = this.main.querySelectorAll(&#39;.guanbi&#39;);
        this.spans = this.main.querySelectorAll(&#39;.fisrstnav li span:first-child&#39;);
    }
    //1.切换功能
    toggleTab() {
        that.clearClass();
        this.className = &#39;liactive&#39;;
        that.sections[this.index].className = &#39;conactive&#39;;
    }
    clearClass() {
        for (var i = 0; i &lt; this.lis.length; i++) {
            this.lis[i].className = &#39;&#39;;
            this.sections[i].className = &#39;&#39;;
        }
    }
    //2.添加功能
    addTab() {
        that.clearClass();
        var random = parseInt(Math.random() * 100);
        var li = &#39;&lt;li class=&quot;liactive&quot;&gt;&lt;span&gt; 测试&#39; + random + &#39; &lt;/span&gt;&lt;span class = &quot;guanbi&quot;&gt;x&lt;/span&gt;&lt;/li&gt;&#39;;
        var section = &#39;&lt;section class=&quot;conactive&quot;&gt;测试&#39; + random + &#39;&lt;/section&gt;&#39;
        that.ul.insertAdjacentHTML(&#39;beforeend&#39;, li);
        that.fsection.insertAdjacentHTML(&#39;beforeend&#39;, section);
        that.init();
    }
    //3.删除功能
    removeTab(e) {
        e.stopPropagation(); // 阻止冒泡
        var index = this.parentNode.index;
        that.lis[index].remove();
        that.sections[index].remove();
        that.init();
        // 当删除的不是选中状态的li的时候,原来的选中状态li保持不变
        if (document.querySelector(&#39;.liactive&#39;)) return;
        that.lis[index - 1] &amp;&amp; that.lis[index - 1].click();
    }
    //4.修改功能
    editTab() {
        var str = this.innerHTML;
        // 双击禁止选定文字
        window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
        this.innerHTML = &#39;&lt;input type=&quot;text&quot; /&gt;&#39;
        var input = this.children[0];
        input.value = str;
        input.select(); // 文本框里面的文字处于选定状态
        // 当文本框失去焦点时，就把文字给span
        input.onblur = function() {
            this.parentNode.innerHTML = this.value
        }
        // 当按下回车时，就把文字给span
        input.onkeyup = function(e) {
            if(e.keyCode === 13){
                this.blur();
            }
        }
    }
}
new Tab(&#39;#tab&#39;);
</code></pre>
</li>
</ul>
<h2 id="构造函数和原型"><a href="#构造函数和原型" class="headerlink" title="构造函数和原型"></a>构造函数和原型</h2><h3 id="对象的三种创建方式–复习"><a href="#对象的三种创建方式–复习" class="headerlink" title="对象的三种创建方式–复习"></a>对象的三种创建方式–复习</h3><pre><code class="js">//字面量方式
var obj = {};
//new关键字
var obj = new Object();
//构造函数方式
function Person(name,age){
  this.name = name;
  this.age = age;
  this.sing = function(){
      console.log(&#39;我会唱歌&#39;)
  }
}
var obj = new Person(&#39;zs&#39;,12);</code></pre>
<p>构造函数是一种特殊的函数，主要用来初始化对象，即为对象成员变量赋初始值，它总与new一起使用。我们可以把对象中一些公共的属性和方法抽取出来，然后封装到这个函数里面。<br>在JS中，使用构造函数时要注意以下两点：<br>1.构造函数用于创建某类对象，其首字母要大写<br>2.构造函数要和new一起使用才有意义</p>
<p>new在执行时会做四件事情：<br>①在内存中创建一个新的空对象<br>②让this指向这个新的对象<br>③执行构造函数里面的代码，给这个新对象添加属性和方法。<br>④返回这个新对象（所以构造函数里面不需要 return）。</p>
<h3 id="静态成员和实例成员"><a href="#静态成员和实例成员" class="headerlink" title="静态成员和实例成员"></a>静态成员和实例成员</h3><h4 id="实例成员"><a href="#实例成员" class="headerlink" title="实例成员"></a>实例成员</h4><p>实例成员就是构造函数内部通过this添加的成员 如下列代码中uname age sing 就是实例成员,实例成员只能通过实例化的对象来访问</p>
<pre><code class="js">function Star(uname, age) {
    this.uname = uname;
    this.age = age;
    this.sing = function() {
        console.log(&#39;我会唱歌&#39;);
    }
}
var ldh = new Star(&#39;刘德华&#39;, 18);
console.log(ldh.uname);//实例成员只能通过实例化的对象来访问</code></pre>
<h4 id="静态成员"><a href="#静态成员" class="headerlink" title="静态成员"></a>静态成员</h4><p>静态成员 在构造函数本身上添加的成员  如下列代码中 sex 就是静态成员,静态成员只能通过构造函数来访问</p>
<pre><code class="js"> function Star(uname, age) {
     this.uname = uname;
     this.age = age;
     this.sing = function() {
     console.log(&#39;我会唱歌&#39;);
    }
}
Star.sex = &#39;男&#39;;
var ldh = new Star(&#39;刘德华&#39;, 18);
console.log(Star.sex);//静态成员只能通过构造函数来访问
console.log(ldh.sex);//undefined</code></pre>
<h3 id="构造函数的问题"><a href="#构造函数的问题" class="headerlink" title="构造函数的问题"></a>构造函数的问题</h3><p>构造函数方法很好用，但是存在浪费内存的问题。因为对象中的方法是复杂数据类型，所以又要开辟新的内存空间来存放方法。</p>
<p><img src="http://helloxx.cn/d2img1.png" srcset="/myblog/img/loading.gif" alt=""></p>
<pre><code> console.log(ldh.sing === zxy.sing);//false</code></pre><h3 id="构造函数原型prototype"><a href="#构造函数原型prototype" class="headerlink" title="构造函数原型prototype"></a>构造函数原型prototype</h3><p>构造函数通过原型分配的函数是所有对象所共享的。</p>
<p>JavaScript 规定，每一个构造函数都有一个prototype 属性，指向另一个对象。注意这个prototype就是一个对象，这个对象的所有属性和方法，都会被构造函数所拥有。</p>
<p>我们可以把那些不变的方法，直接定义在 prototype 对象上，这样所有对象的实例就可以共享这些方法。</p>
<pre><code class="js">function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}
Star.prototype.sing = function() {
    console.log(&#39;我会唱歌&#39;);
}
var ldh = new Star(&#39;刘德华&#39;, 18);
var zxy = new Star(&#39;张学友&#39;, 19);
ldh.sing();//我会唱歌
zxy.sing();//我会唱歌
console.log(ldh.sing === zxy.sing);//true</code></pre>
<h3 id="对象原型-proto"><a href="#对象原型-proto" class="headerlink" title="对象原型__ proto __"></a>对象原型__ proto __</h3><p>对象都会有一个属性 <code>__proto__</code> ，指向构造函数的 prototype 原型对象，之所以我们对象可以使用构造函数 prototype 原型对象的属性和方法，就是因为对象有 <code>__proto__</code> 原型的存在。<br><code>__proto__</code> 对象原型和原型对象 prototype 是等价的<br><code>__proto__</code>对象原型的意义就在于为对象的查找机制提供一个方向，或者说一条路线，但是它是一个非标准属性，因此实际开发中，不可以使用这个属性，它只是内部指向原型对象 prototype</p>
<p><img src="http://helloxx.cn/d2img2.png" srcset="/myblog/img/loading.gif" alt=""></p>
<pre><code class="js">function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}
Star.prototype.sing = function () {
    console.log(&#39;我会唱歌&#39;);
}
var ldh = new Star(&#39;刘德华&#39;, 18);
var zxy = new Star(&#39;张学友&#39;, 19);
ldh.sing();//我会唱歌
console.log(ldh);//对象身上系统自己添加一个__proto__指向我们构造函数的原型对象
console.log(ldh.__proto__ === Star.prototype);//true
//方法的查找规则：首先先看1dh对象身上是否有sing方法，如果有就执行这个对象上的sing
//如果没有sing这个方法，因为有__proto__的存在，就去构造函数原型对象 prototype身上去查找sing这个方法</code></pre>
<h3 id="constructor构造函数"><a href="#constructor构造函数" class="headerlink" title="constructor构造函数"></a>constructor构造函数</h3><p>对象原型（ <code>__proto__</code> ）和构造函数（prototype）原型对象里面都有一个属性 constructor 属性 ，constructor 我们称为构造函数，因为它指回构造函数本身。<br>constructor 主要用于记录该对象引用于哪个构造函数，它可以让原型对象重新指向原来的构造函数。<br>一般情况下，对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法，我们可以给原型对象采取对象形式赋值，但是这样就会覆盖构造函数原型对象原来的内容，这样修改后的原型对象 constructor  就不再指向当前构造函数了。此时，我们可以在修改后的原型对象中，添加一个 constructor 指向原来的构造函数。</p>
<p>如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数,如:</p>
<pre><code class="js">function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
Star.prototype = {
    // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
    constructor: Star, // 手动设置指回原来的构造函数
    sing: function() {
        console.log(&#39;我会唱歌&#39;);
    },
    movie: function() {
        console.log(&#39;我会演电影&#39;);
    }
}
var zxy = new Star(&#39;张学友&#39;, 19);
console.log(zxy)</code></pre>
<p>以上代码运行结果,设置constructor属性如图:</p>
<p><img src="http://helloxx.cn/jd2img8.png" srcset="/myblog/img/loading.gif" alt="">如果未设置constructor属性,如图:</p>
<p><img src="http://helloxx.cn/d2img9.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="构造函数实例和原型对象三角关系"><a href="#构造函数实例和原型对象三角关系" class="headerlink" title="构造函数实例和原型对象三角关系"></a>构造函数实例和原型对象三角关系</h3><pre><code class="js">1.构造函数的prototype属性指向了构造函数原型对象
2.实例对象是由构造函数创建的,实例对象的__proto__属性指向了构造函数的原型对象
3.构造函数的原型对象的constructor属性指向了构造函数,实例对象的原型的constructor属性也指向了构造函数</code></pre>
<p><img src="http://helloxx.cn/d2img4.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="原型链"><a href="#原型链" class="headerlink" title="原型链"></a>原型链</h3><p>​    每一个实例对象又有一个<code>__proto__</code> 属性，指向的构造函数的原型对象，构造函数的原型对象也是一个对象，也有<code>__proto__</code>属性，这样一层一层往上找就形成了原型链。</p>
<p><img src="http://helloxx.cn/jd2img5.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="原型链和成员的查找机制"><a href="#原型链和成员的查找机制" class="headerlink" title="原型链和成员的查找机制"></a>原型链和成员的查找机制</h3><p>任何对象都有原型对象,也就是prototype属性,任何原型对象也是一个对象,该对象就有__ proto __属性,这样一层一层往上找,就形成了一条链,我们称此为原型链</p>
<p>当访问一个对象的属性（包括方法）时，首先查找这个对象自身有没有该属性。<br>如果没有就查找它的原型（也就是 <code>__proto__</code> 指向的 prototype 原型对象）。<br>如果还没有就查找原型对象的原型（Object的原型对象）。<br>依此类推一直找到 Object 为止（null）。<br><code>__proto__</code>对象原型的意义就在于为对象成员查找机制提供一个方向，或者说一条路线。</p>
<h3 id="原型对象中this指向"><a href="#原型对象中this指向" class="headerlink" title="原型对象中this指向"></a>原型对象中this指向</h3><p>构造函数中的this和原型对象的this,都指向我们new出来的实例对象</p>
<pre><code class="js">function Star(uname, age) {
    this.uname = uname;
    this.age = age;
}
var that;
Star.prototype.sing = function() {
    console.log(&#39;我会唱歌&#39;);
    that = this;
}
var ldh = new Star(&#39;刘德华&#39;, 18);
ldh.sing();
// 1. 在构造函数中,里面this指向的是对象实例 ldh
console.log(that === ldh);//true
// 2.原型对象函数里面的this 指向的是 实例对象 ldh</code></pre>
<p><img src="http://helloxx.cn/jd2img6.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="通过原型为数组扩展内置方法"><a href="#通过原型为数组扩展内置方法" class="headerlink" title="通过原型为数组扩展内置方法"></a>通过原型为数组扩展内置方法</h3><p>可以通过原型对象，对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。<br>注意：数组和字符串内置对象不能给原型对象覆盖操作 Array.prototype = { }，只能是 Array.prototype.xxx= function( ) { }的方式</p>
<pre><code class="js">console.log(Array.prototype);
//添加求和方法
Array.prototype.sum = function() {
   var sum = 0;
   for (var i = 0; i &lt; this.length; i++) {
   sum += this[i];
   }
   return sum;
 };
 //此时数组对象中已经存在sum()方法了  可以始终 数组.sum()进行数据的求和
var arr = [1,2,3,4];
console.log(arr.sum());//10</code></pre>
<h2 id="继承"><a href="#继承" class="headerlink" title="继承"></a>继承</h2><h3 id="call"><a href="#call" class="headerlink" title="call()"></a>call()</h3><ul>
<li>call()可以调用函数</li>
<li>call()可以修改this的指向,使用call()的时候 参数一是修改后的this指向,参数2,参数3..使用逗号隔开连接</li>
</ul>
<pre><code class="js">function fn(x, y) {
    console.log(this);
    console.log(x + y);
}
var o = {
    name: &#39;andy&#39;
};
fn.call(); // this指向window
fn.call(1,2);//call()可以调用fn函数  
fn.call(o, 1, 2);//调用了函数此时的this指向了对象o,</code></pre>
<p><img src="http://helloxx.cn/d2img10.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="子构造函数继承父构造函数中的属性-ES5中的方法"><a href="#子构造函数继承父构造函数中的属性-ES5中的方法" class="headerlink" title="子构造函数继承父构造函数中的属性(ES5中的方法)"></a>子构造函数继承父构造函数中的属性(ES5中的方法)</h3><ol>
<li>先定义一个父构造函数</li>
<li>再定义一个子构造函数</li>
<li>子构造函数继承父构造函数的属性(使用call方法)</li>
</ol>
<pre><code class="js"> // 1. 父构造函数
 function Father(uname, age) {
   // this 指向父构造函数的对象实例
   this.uname = uname;
   this.age = age;
 }
  // 2 .子构造函数 
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例
  //3.使用call方式实现子继承父的属性
  Father.call(this, uname, age);
  this.score = score;
}
var son = new Son(&#39;刘德华&#39;, 18, 100);
console.log(son);</code></pre>
<p><img src="http://helloxx.cn/jd2img11.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h3 id="借用原型对象继承方法"><a href="#借用原型对象继承方法" class="headerlink" title="借用原型对象继承方法"></a>借用原型对象继承方法</h3><ol>
<li>先定义一个父构造函数</li>
<li>再定义一个子构造函数</li>
<li>子构造函数继承父构造函数的属性(使用call方法)</li>
</ol>
<pre><code class="js">// 1. 父构造函数
function Father(uname, age) {
    // this 指向父构造函数的对象实例
    this.uname = uname;
    this.age = age;
}
Father.prototype.money = function() {
    console.log(100000);
};
// 2 .子构造函数 
function Son(uname, age, score) {
    // this 指向子构造函数的对象实例
    Father.call(this, uname, age);
    this.score = score;
}
// Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father();
// 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
Son.prototype.constructor = Son;
// 这个是子构造函数专门的方法
Son.prototype.exam = function() {
    console.log(&#39;孩子要考试&#39;);
}
var son = new Son(&#39;刘德华&#39;, 18, 100);
console.log(son);</code></pre>
<p>如上代码结果如图:</p>
<p><img src="http://helloxx.cn/jd2img12.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h4 id="类的本质"><a href="#类的本质" class="headerlink" title="类的本质"></a>类的本质</h4><ol>
<li>class本质还是 function.</li>
<li>类的所有方法都定义在类的 prototype属性上</li>
<li>类创建的实例里面也有__ proto __指向类的 prototype原型对象</li>
<li>所以ES6的类它的绝大部分功能，ES5都可以做到，新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已</li>
<li>所以ES6的类其实就是语法糖。</li>
<li>语法糖：语法糖就是一种便捷写法。简单理解，有两种方法可以实现同样的功能但是一种写法更加淸晰、方便,那么这个方法就是语法糖</li>
</ol>
<h2 id="ES5新增方法"><a href="#ES5新增方法" class="headerlink" title="ES5新增方法"></a>ES5新增方法</h2><h3 id="数组方法-forEach遍历数组"><a href="#数组方法-forEach遍历数组" class="headerlink" title="数组方法 forEach遍历数组"></a>数组方法 forEach遍历数组</h3><pre><code class="js"> arr.forEach(function(value, index, array) {
       //参数一是:数组元素,必填
       //参数二是:数组元素的索引，可选
       //参数三是:当前的数组，可选
 })
  //相当于数组遍历的 for循环 没有返回值
var arr = [1, 2, 3];
var sum = 0;
arr.forEach(function(value, index, array){
    console.log(&#39;每个数组元素&#39; + value);
    console.log(&#39;每个数组元素的索引号&#39;+ index);
    conso1e.log(&#39;数组本身&#39; + array);
    sum += value;
})
console.log(sum); // 6

// 箭头函数写法
arr.forEach((ele,idx,val) =&gt; console.log(ele+&#39;---&#39;+idx+&#39;---&#39;+val)); 
4---0---4,5,6
5---1---4,5,6
6---2---4,5,6
</code></pre>
<h3 id="数组方法-map"><a href="#数组方法-map" class="headerlink" title="数组方法 map"></a>数组方法 map</h3><p>map() 方法返回一个新数组，数组中的元素为原始数组元素调用函数处理后的值。</p>
<p>map() 方法按照原始数组元素顺序依次处理元素。map() 不会对空数组进行检测。map() 不会改变原始数组。</p>
<pre><code class="js"> arr.map(function(value, index, array) {
       //参数一是:数组元素,必填
       //参数二是:数组元素的索引
       //参数三是:当前的数组
 })
  //相当于数组遍历的 for循环，返回新数组
var arr = [1, 2, 3];
var sum = arr.map(function(value){
    return value*2
})
console.log(sum);//[2,4,6]
// 箭头函数写法
</code></pre>
<h3 id="数组方法-filter过滤数组"><a href="#数组方法-filter过滤数组" class="headerlink" title="数组方法 filter过滤数组"></a>数组方法 filter过滤数组</h3><p>filter( )方法创建一个新的数组，新数组中的元素是通过检查指定数组中符合条件的所有元素，主要用于筛选数组，注意它直接返回一个新数组</p>
<pre><code class="js">  var arr = [12, 66, 4, 88, 3, 7];
  var newArr = arr.filter(function(value, index,array) {//因为返回的是新的数组，所以要进行赋值操作
       //参数一是:数组元素,必填
     //参数二是:数组元素的索引
     //参数三是:当前的数组
     return value &gt;= 20;
  });
  console.log(newArr);//[66,88] //返回值是一个新数组</code></pre>
<h3 id="数组方法-some"><a href="#数组方法-some" class="headerlink" title="数组方法 some"></a>数组方法 some</h3><pre><code class="js">some 查找数组中是否有满足条件的元素，返回布尔值,如果是空数组，则返回false
 var arr = [10, 30, 4];
 var flag = arr.some(function(value,index,array) {
    //参数一是:数组元素,必填
     //参数二是:数组元素的索引
     //参数三是:当前的数组
     return value &lt; 3;
  });
console.log(flag);//false返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环</code></pre>
<h3 id="数组方法-every"><a href="#数组方法-every" class="headerlink" title="数组方法 every"></a>数组方法 every</h3><pre><code class="js">every 方法用于检测数组所有元素是否都符合指定条件,返回布尔值,如果是空数组，则返回true
var arr = [10, 30, 4];
arr.every(x=&gt; x &gt; 10);// false
arr.every(x =&gt; x &gt; 3); //true</code></pre>
<h3 id="筛选商品案例"><a href="#筛选商品案例" class="headerlink" title="筛选商品案例"></a>筛选商品案例</h3><ol>
<li><p>定义数组对象数据</p>
<pre><code class="js">var data = [{
            id: 1,
            pname: &#39;小米&#39;,
            price: 3999
        }, {
            id: 2,
            pname: &#39;oppo&#39;,
            price: 999
        }, {
            id: 3,
            pname: &#39;荣耀&#39;,
            price: 1299
        }, {
            id: 4,
            pname: &#39;华为&#39;,
            price: 1999
        }, ];</code></pre>
</li>
<li><p>使用forEach遍历数据并渲染到页面中</p>
<pre><code class="js">data.forEach(function(value) {
  var tr = document.createElement(&#39;tr&#39;);
  tr.innerHTML = &#39;&lt;td&gt;&#39; + value.id + &#39;&lt;/td&gt;&lt;td&gt;&#39; + value.pname + &#39;&lt;/td&gt;&lt;td&gt;&#39; + value.price + &#39;&lt;/td&gt;&#39;;
  tbody.appendChild(tr);
 });</code></pre>
</li>
<li><p>根据价格筛选数据</p>
<ol>
<li><p>获取到搜索按钮并为其绑定点击事件</p>
<pre><code class="js">search_price.addEventListener(&#39;click&#39;, function() {
});</code></pre>
</li>
<li><p>使用filter将用户输入的价格信息筛选出来</p>
<pre><code class="js">search_price.addEventListener(&#39;click&#39;, function() {
      var newDate = data.filter(function(value) {
        //start.value是开始区间
        //end.value是结束的区间
          return value.price &gt;= start.value &amp;&amp; value.price &lt;= end.value;
      });
      console.log(newDate);
 });</code></pre>
</li>
<li><p>将筛选出来的数据重新渲染到表格中</p>
<ol>
<li><p>将渲染数据的逻辑封装到一个函数中</p>
<pre><code class="js">function setDate(mydata) {
      // 先清空原来tbody 里面的数据
  tbody.innerHTML = &#39;&#39;;
  mydata.forEach(function(value) {
    var tr = document.createElement(&#39;tr&#39;);
    tr.innerHTML = &#39;&lt;td&gt;&#39; + value.id + &#39;&lt;/td&gt;&lt;td&gt;&#39; + value.pname + &#39;&lt;/td&gt;&lt;td&gt;&#39; + value.price + &#39;&lt;/td&gt;&#39;;
      tbody.appendChild(tr);
  });
 }</code></pre>
</li>
<li><p>将筛选之后的数据重新渲染</p>
<pre><code class="js"> search_price.addEventListener(&#39;click&#39;, function() {
     var newDate = data.filter(function(value) {
     return value.price &gt;= start.value &amp;&amp; value.price &lt;= end.value;
     });
     console.log(newDate);
     // 把筛选完之后的对象渲染到页面中
     setDate(newDate);
});</code></pre>
</li>
</ol>
</li>
<li><p>根据商品名称筛选</p>
<ol>
<li><p>获取用户输入的商品名称</p>
</li>
<li><p>为查询按钮绑定点击事件,将输入的商品名称与这个数据进行筛选</p>
<pre><code class="js"> search_pro.addEventListener(&#39;click&#39;, function() {
     var arr = [];
     data.some(function(value) {
       if (value.pname === product.value) {
         // console.log(value);
         arr.push(value);
         return true; // return 后面必须写true  
       }
     });
     // 把拿到的数据渲染到页面中
     setDate(arr);
})</code></pre>
</li>
</ol>
</li>
</ol>
</li>
</ol>
<h3 id="some和forEach区别"><a href="#some和forEach区别" class="headerlink" title="some和forEach区别"></a>some和forEach区别</h3><ul>
<li>如果查询数组中唯一的元素, 用some方法更合适,在some 里面 遇到 return true 就是终止遍历 迭代效率更高</li>
<li>在forEach 里面 return 不会终止迭代</li>
<li>在filter 里面 return 不会终止迭代</li>
</ul>
<h3 id="trim方法去除字符串两端的空格"><a href="#trim方法去除字符串两端的空格" class="headerlink" title="trim方法去除字符串两端的空格"></a>trim方法去除字符串两端的空格</h3><pre><code class="js">var str = &#39;   hello   &#39;
console.log(str.trim()）  //hello 去除两端空格
var str1 = &#39;   he l l o   &#39;
console.log(str1.trim()）  //he l l o  去除两端空格</code></pre>
<h3 id="获取对象的属性名"><a href="#获取对象的属性名" class="headerlink" title="获取对象的属性名"></a>获取对象的属性名</h3><p>Object.keys(对象) 获取 到当前对象中的属性名 ，返回值是一个数组</p>
<pre><code class="js"> var obj = {
     id: 1,
     pname: &#39;小米&#39;,
     price: 1999,
     num: 2000
};
var result = Object.keys(obj)
console.log(result)//[id,pname,price,num]</code></pre>
<h3 id="Object-defineProperty"><a href="#Object-defineProperty" class="headerlink" title="Object.defineProperty"></a>Object.defineProperty</h3><p>Object.defineProperty设置或修改对象中的属性</p>
<pre><code class="js">Object.defineProperty(对象，修改或新增的属性名，{
        value:修改或新增的属性的值,
        writable:true/false,//如果值为false 不允许修改这个属性值，默认值是false
        enumerable: false,//enumerable 如果值为false 则不允许遍历,默认值是false
        configurable: false  //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性,默认值是false
})    
var obj = {
    id:1,
    pname:&#39;小米&#39;,
    price:1999
}
Object.defineProperty(obj，&#39;num&#39;,{
   value：1000, //新增num
   writable:false,//不允许num 修改
   enumerable:false,//不允许num 遍历
   configurable: false //不允许删除num和该属性的特性
});
console.log(obj);</code></pre>
<h3 id="Object-freeze-冻结对象"><a href="#Object-freeze-冻结对象" class="headerlink" title="Object.freeze 冻结对象"></a>Object.freeze 冻结对象</h3><p><code>Object.freeze()</code>方法可以冻结一个对象。一个被冻结的对象再也不能被修改；冻结了一个对象则不能向这个对象添加新的属性，不能删除已有属性 </p>
<h2 id="函数的定义和调用"><a href="#函数的定义和调用" class="headerlink" title="函数的定义和调用"></a>函数的定义和调用</h2><h3 id="函数的定义方式"><a href="#函数的定义方式" class="headerlink" title="函数的定义方式"></a>函数的定义方式</h3><ol>
<li><p>方式1 函数声明方式 function 关键字 (命名函数)</p>
<pre><code class="js">function fn(){}</code></pre>
</li>
<li><p>方式2 函数表达式(匿名函数)</p>
<pre><code class="js">var fn = function(){}</code></pre>
</li>
<li><p>方式3 new Function() </p>
<pre><code class="js">var f = new Function(&#39;a&#39;, &#39;b&#39;, &#39;console.log(a + b)&#39;);
f(1, 2);

var fn = new Function(&#39;参数1&#39;,&#39;参数2&#39;..., &#39;函数体&#39;)
注意
/*Function 里面参数都必须是字符串格式
第三种方式执行效率低，也不方便书写，因此较少使用
所有函数都是 Function 的实例(对象)  
函数也属于对象
*/
console.log(f instanceof Object)</code></pre>
</li>
</ol>
<h3 id="函数的调用"><a href="#函数的调用" class="headerlink" title="函数的调用"></a>函数的调用</h3><pre><code class="js">//1. 普通函数
function fn() {
    console.log(&#39;人生的巅峰&#39;);
}
 fn(); 
//2. 对象的方法
var o = {
  sayHi: function() {
      console.log(&#39;人生的巅峰&#39;);
  }
}
o.sayHi();
// 3. 构造函数
function Star() {};
new Star();
// 4. 绑定事件函数
 btn.onclick = function() {};   // 点击了按钮就可以调用这个函数
// 5. 定时器函数
setInterval(function() {}, 1000);  //这个函数是定时器自动1秒钟调用一次
// 6. 立即执行函数(自调用函数)
(function() {
    console.log(&#39;人生的巅峰&#39;);
})();</code></pre>
<h2 id="this"><a href="#this" class="headerlink" title="this"></a>this</h2><h3 id="函数内部的this指向"><a href="#函数内部的this指向" class="headerlink" title="函数内部的this指向"></a>函数内部的this指向</h3><p>这些 this 的指向，是当我们调用函数的时候确定的。调用方式的不同决定了this 的指向不同</p>
<p>一般指向我们的调用者.</p>
<table>
<thead>
<tr>
<th>调用方式</th>
<th>this指向</th>
</tr>
</thead>
<tbody><tr>
<td>普通函数调用</td>
<td>window</td>
</tr>
<tr>
<td>构造函数调用</td>
<td>实例对象、原型对象里面的方法也指向实例对象</td>
</tr>
<tr>
<td>对象方法调用</td>
<td>该方所属对象</td>
</tr>
<tr>
<td>事件绑定方法</td>
<td>绑定事件对象</td>
</tr>
<tr>
<td>定时器函数</td>
<td>window</td>
</tr>
<tr>
<td>立即执行函数</td>
<td>window</td>
</tr>
</tbody></table>
<h3 id="改变函数内部-this-指向"><a href="#改变函数内部-this-指向" class="headerlink" title="改变函数内部 this 指向"></a>改变函数内部 this 指向</h3><h4 id="call方法"><a href="#call方法" class="headerlink" title="call方法"></a>call方法</h4><p>call()方法调用一个对象。简单理解为调用函数的方式，但是它可以改变函数的 this 指向</p>
<p>应用场景:  经常做继承. </p>
<pre><code class="js">var o = {
    name: &#39;andy&#39;
}
function fn(a, b) {
    console.log(this);
    console.log(a+b)
};
fn(1,2)// 此时的this指向的是window 运行结果为3
fn.call(o,1,2)//此时的this指向的是对象o,参数使用逗号隔开,运行结果为3</code></pre>
<p>以上代码运行结果为:</p>
<p><img src="http://helloxx.cn/d3img4.png" srcset="/myblog/img/loading.gif" alt=""></p>
<h4 id="apply方法"><a href="#apply方法" class="headerlink" title="apply方法"></a>apply方法</h4><p>apply() 方法调用一个函数。简单理解为调用函数的方式，但是它可以改变函数的 this 指向，参数必须是数组形式</p>
<p>应用场景:  经常跟数组有关系</p>
<pre><code class="js">var o = {
    name: &#39;andy&#39;
}
function fn(a, b) {
    console.log(this);
    console.log(a+b)
};
fn()// 此时的this指向的是window 运行结果为3
fn.apply(o,[1,2])//此时的this指向的是对象o,参数使用数组传递 运行结果为3
//1.apply()是调用函数,第二个可以改变函数内部的this指向
//2.但是他的参数必须是数组（伪数组）
//3. apply的主要应用 比如说我们可以利用appy借助于数学内置对象求最大值
var arr=[1,66,3,99,4];
var max = Math.max.apply(null, arr);//没有指向则可以写null，但通常写this的指向，这里的null应该写成Math,因应严格模式下，null会有问题
console.log(max);//99</code></pre>
<h4 id="bind方法"><a href="#bind方法" class="headerlink" title="bind方法"></a>bind方法</h4><p>bind() 方法不会调用函数,但是能改变函数内部this 指向,返回由指定的this值和初始化参数改造的原函数拷贝</p>
<p>如果只是想改变 this 指向，并且不想调用这个函数的时候，可以使用bind</p>
<p>应用场景:不调用函数,但是还想改变this指向</p>
<pre><code class="js"> var o = {
 name: &#39;andy&#39;
 };

function fn(a, b) {
    console.log(this);
    console.log(a + b);
};
var f = fn.bind(o, 1, 2); //此处的f是bind返回的新函数
f();//调用新函数  this指向的是对象o 参数使用逗号隔开</code></pre>
<p><img src="http://helloxx.cn/d3img5.png" srcset="/myblog/img/loading.gif" alt=""></p>
<pre><code class="js">//我们有一个按钮，当我们点击了之后，就禁用这个按钮，3秒钟之后开启这个按钮
var btn = document.querySelector(&#39;button&#39;);
btn.onclick = function(){
    this.disabled = true;//这个this指向的是btn这个按钮
    // var that = this;
    setTimeout(function(){
        //that. disabled= false；//定时器函数里面的this指向的是 window 
        this.disabled = false;//定时器函数里面的this指向的是 window
    }.bind(this),3000);//这个this指向的是btn这个对象</code></pre>
<h4 id="call、apply、bind三者的异同"><a href="#call、apply、bind三者的异同" class="headerlink" title="call、apply、bind三者的异同"></a>call、apply、bind三者的异同</h4><ul>
<li>共同点 : 都可以改变this指向</li>
<li>不同点:<ul>
<li>call 和 apply  会调用函数, 并且改变函数内部this指向.</li>
<li>call 和 apply传递的参数不一样,call传递参数使用逗号隔开,apply使用数组传递</li>
<li>bind  不会调用函数, 可以改变函数内部this指向.</li>
</ul>
</li>
</ul>
<ul>
<li>应用场景<ol>
<li>call 经常做继承. </li>
<li>apply经常跟数组有关系.  比如借助于数学对象实现数组最大值最小值</li>
<li>bind  不调用函数,但是还想改变this指向. 比如改变定时器内部的this指向. </li>
</ol>
</li>
</ul>
<h2 id="严格模式"><a href="#严格模式" class="headerlink" title="严格模式"></a>严格模式</h2><h3 id="什么是严格模式"><a href="#什么是严格模式" class="headerlink" title="什么是严格模式"></a>什么是严格模式</h3><p>JavaScript 除了提供正常模式外，还提供了严格模式（strict mode）。ES5 的严格模式是采用具有限制性 JavaScript变体的一种方式，即在严格的条件下运行 JS 代码。</p>
<p>严格模式在 IE10 以上版本的浏览器中才会被支持，旧版本浏览器中会被忽略。</p>
<p>严格模式对正常的 JavaScript 语义做了一些更改： </p>
<p>1.消除了 Javascript 语法的一些不合理、不严谨之处，减少了一些怪异行为。</p>
<p>2.消除代码运行的一些不安全之处，保证代码运行的安全。</p>
<p>3.提高编译器效率，增加运行速度。</p>
<p>4.禁用了在 ECMAScript 的未来版本中可能会定义的一些语法，为未来新版本的 Javascript 做好铺垫。比如一些保留字如：class,enum,export, extends, import, super 不能做变量名</p>
<h3 id="开启严格模式"><a href="#开启严格模式" class="headerlink" title="开启严格模式"></a>开启严格模式</h3><p>严格模式可以应用到整个脚本或个别函数中。因此在使用时，我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式两种情况。</p>
<ul>
<li><p>情况一 :为脚本开启严格模式</p>
<ul>
<li><p>有的 script 脚本是严格模式，有的 script 脚本是正常模式，这样不利于文件合并，所以可以将整个脚本文件放在一个立即执行的匿名函数之中。这样独立创建一个作用域而不影响其他<br>script 脚本文件。</p>
<pre><code class="js">(function (){
  //在当前的这个自调用函数中有开启严格模式，当前函数之外还是普通模式
　　　　&quot;use strict&quot;;
       var num = 10;
　　　　function fn() {}
})();
//或者 
&lt;script&gt;
  　&quot;use strict&quot;; //当前script标签开启了严格模式
&lt;/script&gt;
&lt;script&gt;
              //当前script标签未开启严格模式
&lt;/script&gt;</code></pre>
</li>
</ul>
</li>
<li><p>情况二: 为函数开启严格模式</p>
<ul>
<li><p>要给某个函数开启严格模式，需要把“use strict”;  (或 ‘use strict’; ) 声明放在函数体所有语句之前。</p>
<pre><code class="js">function fn(){
　　&quot;use strict&quot;;
　　return &quot;123&quot;;
} 
//当前fn函数开启了严格模式</code></pre>
</li>
</ul>
</li>
</ul>
<h3 id="严格模式中的变化"><a href="#严格模式中的变化" class="headerlink" title="严格模式中的变化"></a>严格模式中的变化</h3><p>严格模式对 Javascript 的语法和行为，都做了一些改变。</p>
<pre><code class="js">&#39;use strict&#39;
num = 10 
console.log(num)//严格模式未声明的变量不允许赋值
--------------------------------------------------------------------------------
var num2 = 1;
delete num2;//严格模式不允许删除变量
--------------------------------------------------------------------------------
function fn() {
 console.log(this); // 严格模式下全局作用域中函数中的 this 是 undefined
}
fn();  
---------------------------------------------------------------------------------
function Star() {
     this.sex = &#39;男&#39;;
}
// Star();严格模式下,如果 构造函数不加new调用, this 指向的是undefined 如果给他赋值则 会报错.
var ldh = new Star();
console.log(ldh.sex);
----------------------------------------------------------------------------------
setTimeout(function() {
  console.log(this); //严格模式下，定时器 this 还是指向 window
}, 2000);  
----------------------------------------------------------------------------------
function fn(a,a){
    console.log(a+a);
}
fn(1,2);//严格模式下，函数不能有重名的参数
//函数必须声明在顶层新版本的 JavaScript会引入 块级作用域（ES6中已引入）。为了与新版本接轨，不允许在非函数的代码块内声明函数。
</code></pre>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode" target="_blank" rel="noopener">更多严格模式要求参考</a></p>
<h2 id="高阶函数"><a href="#高阶函数" class="headerlink" title="高阶函数"></a>高阶函数</h2><p>高阶函数是对其他函数进行操作的函数，它接收函数作为参数或将函数作为返回值输出。</p>
<p><img src="http://helloxx.cn/jd3img2.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p>此时fn 就是一个高阶函数</p>
<p>函数也是一种数据类型，同样可以作为参数，传递给另外一个参数使用。最典型的就是作为回调函数。</p>
<p>同理函数也可以作为返回值传递回来</p>
<h2 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h2><h3 id="变量的作用域复习"><a href="#变量的作用域复习" class="headerlink" title="变量的作用域复习"></a>变量的作用域复习</h3><p>变量根据作用域的不同分为两种：全局变量和局部变量。</p>
<ol>
<li>函数内部可以使用全局变量。</li>
<li>函数外部不可以使用局部变量。</li>
<li>当函数执行完毕，本作用域内的局部变量会销毁。</li>
</ol>
<h3 id="什么是闭包"><a href="#什么是闭包" class="headerlink" title="什么是闭包"></a>什么是闭包</h3><p>闭包（closure）指有权访问另一个函数作用域中变量的函数。简单理解就是 ，一个作用域可以访问另外一个函数内部的局部变量。 </p>
<pre><code class="js">function fn1() { // fn1就是闭包函数
    var num = 10
    function fn2() {
        console.log(num)
    }
    fn2()
}
fn1</code></pre>
<h3 id="闭包的作用"><a href="#闭包的作用" class="headerlink" title="闭包的作用"></a>闭包的作用</h3><p>作用：延伸变量的作用范围。</p>
<pre><code class="js">function fn() {
    var num = 10;
    function fun() {
        console.log(num);
    }
    return fun;
}
var f = fn();
f();</code></pre>
<h3 id="闭包的案例"><a href="#闭包的案例" class="headerlink" title="闭包的案例"></a>闭包的案例</h3><ol>
<li>利用闭包的方式得到当前li 的索引号</li>
</ol>
<pre><code class="js">for (var i = 0; i &lt; lis.length; i++) {
// 利用for循环创建了4个立即执行函数
// 立即执行函数也成为小闭包因为立即执行函数里面的任何一个函数都可以使用它的i这变量
(function(i) {
    lis[i].onclick = function() {
      console.log(i);
    }
 })(i);
}</code></pre>
<ol start="2">
<li>闭包应用-3秒钟之后,打印所有li元素的内容</li>
</ol>
<pre><code class="js"> for (var i = 0; i &lt; lis.length; i++) {
   (function(i) {
     setTimeout(function() {
     console.log(lis[i].innerHTML);
     }, 3000)
   })(i);
}</code></pre>
<ol start="3">
<li>闭包应用-计算打车价格 </li>
</ol>
<pre><code class="js">/*需求分析
打车起步价13(3公里内),  之后每多一公里增加 5块钱.  用户输入公里数就可以计算打车价格
如果有拥堵情况,总价格多收取10块钱拥堵费*/

 var car = (function() {
     var start = 13; // 起步价  局部变量
     var total = 0; // 总价  局部变量
     return {
       // 正常的总价
       price: function(n) {
         if (n &lt;= 3) {
           total = start;
         } else {
           total = start + (n - 3) * 5
         }
         return total;
       },
       // 拥堵之后的费用
       yd: function(flag) {
         return flag ? total + 10 : total;
       }
    }
 })();
console.log(car.price(5)); // 23
console.log(car.yd(true)); // 33</code></pre>
<h3 id="案例"><a href="#案例" class="headerlink" title="案例"></a>案例</h3><pre><code class="js"> var name = &quot;The Window&quot;;
   var object = {
     name: &quot;My Object&quot;,
     getNameFunc: function() {
     return function() {
     return this.name;
     };
   }
 };
console.log(object.getNameFunc()())
-----------------------------------------------------------------------------------
var name = &quot;The Window&quot;;　　
  var object = {　　　　
    name: &quot;My Object&quot;,
    getNameFunc: function() {
    var that = this;
    return function() {
    return that.name;
    };
  }
};
console.log(object.getNameFunc()())
</code></pre>
<h2 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h2><h3 id="什么是递归"><a href="#什么是递归" class="headerlink" title="什么是递归"></a>什么是递归</h3><p><strong>递归：</strong>如果一个函数在内部可以调用其本身，那么这个函数就是递归函数。简单理解:函数内部自己调用自己, 这个函数就是递归函数</p>
<p><strong>注意：</strong>递归函数的作用和循环效果一样，由于递归很容易发生“栈溢出”错误（stack overflow），所以必须要加退出条件return。</p>
<h3 id="利用递归求1-n的阶乘"><a href="#利用递归求1-n的阶乘" class="headerlink" title="利用递归求1~n的阶乘"></a>利用递归求1~n的阶乘</h3><pre><code class="js">//利用递归函数求1~n的阶乘 1 * 2 * 3 * 4 * ..n
 function fn(n) {
     if (n == 1) { //结束条件
       return 1;
     }
     return n * fn(n - 1);
 }
 console.log(fn(3)); // 6</code></pre>
<h3 id="利用递归求斐波那契数列"><a href="#利用递归求斐波那契数列" class="headerlink" title="利用递归求斐波那契数列"></a>利用递归求斐波那契数列</h3><pre><code class="js">// 利用递归函数求斐波那契数列(兔子序列)  1、1、2、3、5、8、13、21...
// 用户输入一个数字 n 就可以求出 这个数字对应的兔子序列值
// 我们只需要知道用户输入的n 的前面两项(n-1 n-2)就可以计算出n 对应的序列值
function fb(n) {
  if (n === 1 || n === 2) {
        return 1;
  }
  return fb(n - 1) + fb(n - 2);
}
console.log(fb(3));</code></pre>
<h3 id="利用递归遍历数据"><a href="#利用递归遍历数据" class="headerlink" title="利用递归遍历数据"></a>利用递归遍历数据</h3><pre><code class="js">// 我们想要做输入id号,就可以返回的数据对象
 var data = [{
   id: 1,
   name: &#39;家电&#39;,
   goods: [{
     id: 11,
     gname: &#39;冰箱&#39;,
     goods: [{
       id: 111,
       gname: &#39;海尔&#39;
     }, {
       id: 112,
       gname: &#39;美的&#39;
     },

            ]

   }, {
     id: 12,
     gname: &#39;洗衣机&#39;
   }]
 }, {
   id: 2,
   name: &#39;服饰&#39;
}];
//1.利用 forEach 去遍历里面的每一个对象
 function getID(json, id) {
   var o = {};
   json.forEach(function(item) {
     // console.log(item); // 2个数组元素
     if (item.id == id) {
       // console.log(item);
       o = item;
       return o;
       // 2. 我们想要得里层的数据 11 12 可以利用递归函数
       // 里面应该有goods这个数组并且数组的长度不为 0 
     } else if (item.goods &amp;&amp; item.goods.length &gt; 0) {
       o = getID(item.goods, id);
     }
   });
   return o;
}</code></pre>
<h2 id="正则表达式概述"><a href="#正则表达式概述" class="headerlink" title="正则表达式概述"></a>正则表达式概述</h2><h3 id="什么是正则表达式"><a href="#什么是正则表达式" class="headerlink" title="什么是正则表达式"></a>什么是正则表达式</h3><p>正则表达式（ Regular Expression ）是用于匹配字符串中字符组合的模式。在JavaScript中，正则表达式也是对象。</p>
<p>正则表通常被用来检索、替换那些符合某个模式（规则）的文本，例如验证表单：用户名表单只能输入英文字母、数字或者下划线， 昵称输入框中可以输入中文(匹配)。此外，正则表达式还常用于过滤掉页面内容中的一些敏感词(替换)，或从字符串中获取我们想要的特定部分(提取)等 。</p>
<p>其他语言也会使用正则表达式，本阶段我们主要是利用JavaScript 正则表达式完成表单验证。</p>
<h3 id="正则表达式的特点"><a href="#正则表达式的特点" class="headerlink" title="正则表达式的特点"></a>正则表达式的特点</h3><ol>
<li>灵活性、逻辑性和功能性非常的强。</li>
<li>可以迅速地用极简单的方式达到字符串的复杂控制。</li>
<li>对于刚接触的人来说，比较晦涩难懂。比如：^\w+([-+.]\w+)<em>@\w+([-.]\w+)*.\w+([-.]\w+)</em>$</li>
<li>实际开发,一般都是直接复制写好的正则表达式. 但是要求会使用正则表达式并且根据实际情况修改正则表达式.   比如用户名:   /^[a-z0-9_-]{3,16}$/</li>
</ol>
<h2 id="正则表达式在js中的使用"><a href="#正则表达式在js中的使用" class="headerlink" title="正则表达式在js中的使用"></a>正则表达式在js中的使用</h2><h3 id="正则表达式的创建"><a href="#正则表达式的创建" class="headerlink" title="正则表达式的创建"></a>正则表达式的创建</h3><p>在 JavaScript 中，可以通过两种方式创建一个正则表达式。</p>
<p>方式一：通过调用RegExp对象的构造函数创建 </p>
<pre><code class="js">var regexp = new RegExp(/123/);
console.log(regexp);</code></pre>
<p>方式二：利用字面量创建 正则表达式</p>
<pre><code class="js"> var rg = /123/;</code></pre>
<h3 id="测试正则表达式"><a href="#测试正则表达式" class="headerlink" title="测试正则表达式"></a>测试正则表达式</h3><p>test() 正则对象方法，用于检测字符串是否符合该规则，该对象会返回 true 或 false，其参数是测试字符串。</p>
<pre><code class="js">var rg = /123/;
console.log(rg.test(123));//匹配字符中是否出现123  出现结果为true
console.log(rg.test(&#39;abc&#39;));//匹配字符中是否出现abc 未出现结果为false</code></pre>
<h2 id="正则表达式中的特殊字符"><a href="#正则表达式中的特殊字符" class="headerlink" title="正则表达式中的特殊字符"></a>正则表达式中的特殊字符</h2><h3 id="正则表达式的组成"><a href="#正则表达式的组成" class="headerlink" title="正则表达式的组成"></a>正则表达式的组成</h3><p>一个正则表达式可以由简单的字符构成，比如 /abc/，也可以是简单和特殊字符的组合，比如 /ab*c/ 。其中特殊字符也被称为元字符，在正则表达式中是具有特殊意义的专用符号，如 ^ 、$ 、+ 等。</p>
<p>特殊字符非常多，可以参考： </p>
<p><a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions" target="_blank" rel="noopener">MDN</a></p>
<p>jQuery 手册：正则表达式部分</p>
<p><a href="<http://tool.oschina.net/regex">正则测试工具</a></p>
<h3 id="边界符"><a href="#边界符" class="headerlink" title="边界符"></a>边界符</h3><p>正则表达式中的边界符（位置符）用来提示字符所处的位置，主要有两个字符</p>
<table>
<thead>
<tr>
<th>边界符</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>^</td>
<td>表示匹配行首的文本（以谁开始）</td>
</tr>
<tr>
<td>$</td>
<td>表示匹配行尾的文本（以谁结束）</td>
</tr>
</tbody></table>
<p>如果 ^和 $ 在一起，表示必须是精确匹配。</p>
<pre><code class="js">var rg = /abc/; // 正则表达式里面不需要加引号 不管是数字型还是字符串型
// /abc/ 只要包含有abc这个字符串返回的都是true
console.log(rg.test(&#39;abc&#39;));
console.log(rg.test(&#39;abcd&#39;));
console.log(rg.test(&#39;aabcd&#39;));
console.log(&#39;---------------------------&#39;);
var reg = /^abc/;
console.log(reg.test(&#39;abc&#39;)); // true
console.log(reg.test(&#39;abcd&#39;)); // true
console.log(reg.test(&#39;aabcd&#39;)); // false
console.log(&#39;---------------------------&#39;);
var reg1 = /^abc$/; // 精确匹配 要求必须是 abc字符串才符合规范
console.log(reg1.test(&#39;abc&#39;)); // true
console.log(reg1.test(&#39;abcd&#39;)); // false
console.log(reg1.test(&#39;aabcd&#39;)); // false
console.log(reg1.test(&#39;abcabc&#39;)); // false</code></pre>
<h3 id="字符类"><a href="#字符类" class="headerlink" title="字符类"></a>字符类</h3><p>字符类表示有一系列字符可供选择，只要匹配其中一个就可以了。所有可供选择的字符都放在方括号内。</p>
<h4 id="方括号"><a href="#方括号" class="headerlink" title="[] 方括号"></a>[] 方括号</h4><p>表示有一系列字符可供选择，只要匹配其中一个就可以了</p>
<pre><code class="js">var rg = /[abc]/; // 只要包含a 或者 包含b 或者包含c 都返回为true
console.log(rg.test(&#39;andy&#39;));//true
console.log(rg.test(&#39;baby&#39;));//true
console.log(rg.test(&#39;color&#39;));//true
console.log(rg.test(&#39;red&#39;));//false
var rg1 = /^[abc]$/; // 三选一 只有是a 或者是 b  或者是c 这三个字母才返回 true
console.log(rg1.test(&#39;aa&#39;));//false
console.log(rg1.test(&#39;a&#39;));//true
console.log(rg1.test(&#39;b&#39;));//true
console.log(rg1.test(&#39;c&#39;));//true
console.log(rg1.test(&#39;abc&#39;));//true
----------------------------------------------------------------------------------
var reg = /^[a-z]$/ //26个英文字母任何一个字母返回 true  - 表示的是a 到z 的范围  
console.log(reg.test(&#39;a&#39;));//true
console.log(reg.test(&#39;z&#39;));//true
console.log(reg.test(&#39;A&#39;));//false
-----------------------------------------------------------------------------------
//字符组合
var reg1 = /^[a-zA-Z0-9]$/; // 26个英文字母(大写和小写都可以)任何一个字母以及数字返回 true  
------------------------------------------------------------------------------------
//取反 方括号内部加上 ^ 表示取反，只要包含方括号内的字符，都返回 false 。
var reg2 = /^[^a-zA-Z0-9]$/;
console.log(reg2.test(&#39;a&#39;));//false
console.log(reg2.test(&#39;B&#39;));//false
console.log(reg2.test(8));//false
console.log(reg2.test(&#39;!&#39;));//true</code></pre>
<h4 id="量词符"><a href="#量词符" class="headerlink" title="量词符"></a>量词符</h4><p>量词符用来设定某个模式出现的次数。</p>
<table>
<thead>
<tr>
<th>量词</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>*</td>
<td>重复0次或更多次</td>
</tr>
<tr>
<td>+</td>
<td>重复1次或更多次</td>
</tr>
<tr>
<td>?</td>
<td>重复0次或1次</td>
</tr>
<tr>
<td>{n}</td>
<td>重复n次</td>
</tr>
<tr>
<td>{n,}</td>
<td>重复n次或更多次</td>
</tr>
<tr>
<td>{n,m}</td>
<td>重复n到m次</td>
</tr>
</tbody></table>
<pre><code class="js">// *相当于&gt;=0 可以出现0次或者很多次
var reg=/^a*$/;
console.log(reg.test(&#39;&#39;));//true
console.log(reg.test(&#39;a&#39;));//true
console.log(reg.test(&#39;aaaa&#39;));//true

// +相当于&gt;=1 可以出现1次或者很多次
var reg1=/^a+$/;
console.log(reg1.test(&#39;&#39;));//false
console.log(reg1.test(&#39;a&#39;));//true
console.log(reg1.test(&#39;aaaa&#39;));//true

// ? 相当于1||0 可以出现0次或者1次
var reg1=/^a?$/;
console.log(reg1.test(&#39;&#39;));//true
console.log(reg1.test(&#39;a&#39;));//true
console.log(reg1.test(&#39;aaaa&#39;));//false


// {3} 就是重复3次
var reg1=/^a{3}$/;
console.log(reg1.test(&#39;&#39;));//false
console.log(reg1.test(&#39;a&#39;));//false
console.log(reg1.test(&#39;aaa&#39;));//true

// {3,} 就是重复3次及以上
var reg1=/^a{3}$/;
console.log(reg1.test(&#39;&#39;));//false
console.log(reg1.test(&#39;aaa&#39;));//true
console.log(reg1.test(&#39;aaaaaa&#39;));//true

// {3,6} 大于等于3并且小于等于6次
var reg1=/^a{3,6}$/;
console.log(reg1.test(&#39;&#39;));//false
console.log(reg1.test(&#39;a&#39;));//false
console.log(reg1.test(&#39;aaa&#39;));//true
console.log(reg1.test(&#39;aaaaaa&#39;));//true
console.log(reg1.test(&#39;aaaaaaaaaa&#39;));//false


</code></pre>
<h4 id="用户名表单验证"><a href="#用户名表单验证" class="headerlink" title="用户名表单验证"></a>用户名表单验证</h4><p>功能需求:</p>
<ol>
<li>如果用户名输入合法, 则后面提示信息为:  用户名合法,并且颜色为绿色</li>
<li>如果用户名输入不合法, 则后面提示信息为:  用户名不符合规范, 并且颜色为红色</li>
</ol>
<p><img src="http://helloxx.cn/d4img2.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p><img src="http://helloxx.cn/jd4img1.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p>分析:</p>
<ol>
<li>用户名只能为英文字母,数字,下划线或者短横线组成, 并且用户名长度为6~16位.</li>
<li>首先准备好这种正则表达式模式/$[a-zA-Z0-9-_]{6,16}^/</li>
<li>当表单失去焦点就开始验证. </li>
<li>如果符合正则规范, 则让后面的span标签添加 right类.</li>
<li>如果不符合正则规范, 则让后面的span标签添加 wrong类.</li>
</ol>
<pre><code class="js">&lt;input type=&quot;text&quot; class=&quot;uname&quot;&gt; &lt;span&gt;请输入用户名&lt;/span&gt;
 &lt;script&gt;
 //  量词是设定某个模式出现的次数
 var reg = /^[a-zA-Z0-9_-]{6,16}$/; // 这个模式用户只能输入英文字母 数字 下划线 中划线
 var uname = document.querySelector(&#39;.uname&#39;);
 var span = document.querySelector(&#39;span&#39;);
 uname.onblur = function() {
   if (reg.test(this.value)) {
   console.log(&#39;正确的&#39;);
   span.className = &#39;right&#39;;
   span.innerHTML = &#39;用户名格式输入正确&#39;;
   } else {
   console.log(&#39;错误的&#39;);
   span.className = &#39;wrong&#39;;
   span.innerHTML = &#39;用户名格式输入不正确&#39;;
   }
 }
&lt;/script&gt;</code></pre>
<h4 id="括号总结"><a href="#括号总结" class="headerlink" title="括号总结"></a>括号总结</h4><p>1.大括号  量词符.  里面表示重复次数</p>
<p>2.中括号 字符集合。匹配方括号中的任意字符. </p>
<p>3.小括号表示优先级</p>
<p><a href="https://c.runoob.com/" target="_blank" rel="noopener">正则表达式在线测试</a></p>
<h3 id="预定义类"><a href="#预定义类" class="headerlink" title="预定义类"></a>预定义类</h3><p>预定义类指的是某些常见模式的简写方式.</p>
<table>
<thead>
<tr>
<th>预定类</th>
<th>说明</th>
</tr>
</thead>
<tbody><tr>
<td>\d</td>
<td>匹配0-9之间的任一数字，相当于[0-9]</td>
</tr>
<tr>
<td>\D</td>
<td>匹配所有0-9以外的字符，相当于<code>[^0-9]</code></td>
</tr>
<tr>
<td>\w</td>
<td>匹配任意的字母、数字和下划线，相当于[A-Za-z0-9]</td>
</tr>
<tr>
<td>\W</td>
<td>除所有字母、数字和下划线以外的字符，相当于<code>[^A-Za-z0-9_]</code></td>
</tr>
<tr>
<td>\s</td>
<td>匹配空格（包换行符、制表符、空格符等），相当于[\t\r\n\v\f]</td>
</tr>
<tr>
<td>\S</td>
<td>匹配非空格的字符，相当于<code>[^ \t\r\n\v\f]</code></td>
</tr>
</tbody></table>
<p><strong>案例:验证座机号码</strong></p>
<pre><code class="js">var reg = /^\d{3}-\d{8}|\d{4}-\d{7}$/;
var reg = /^\d{3,4}-\d{7,8}$/;</code></pre>
<p><strong>表单验证案例</strong></p>
<pre><code class="js">//手机号验证:/^1[3|4|5|7|8][0-9]{9}$/;
//验证通过与不通过更换元素的类名与元素中的内容
 if (reg.test(this.value)) {
    // console.log(&#39;正确的&#39;);
    this.nextElementSibling.className = &#39;success&#39;;
    this.nextElementSibling.innerHTML = &#39;&lt;i class=&quot;success_icon&quot;&gt;&lt;/i&gt; 恭喜您输入正确&#39;;
   } else {
       // console.log(&#39;不正确&#39;);
      this.nextElementSibling.className = &#39;error&#39;;
      this.nextElementSibling.innerHTML = &#39;&lt;i class=&quot;error_icon&quot;&gt;&lt;/i&gt;格式不正确,请从新输入 &#39;;
 }</code></pre>
<pre><code class="js">//QQ号验证: /^[1-9]\d{4,}$/; 
//昵称验证:/^[\u4e00-\u9fa5]{2,8}$/
//验证通过与不通过更换元素的类名与元素中的内容 ,将上一步的匹配代码进行封装,多次调用即可
 function regexp(ele, reg) {
    ele.onblur = function() {
      if (reg.test(this.value)) {
        // console.log(&#39;正确的&#39;);
        this.nextElementSibling.className = &#39;success&#39;;
        this.nextElementSibling.innerHTML = &#39;&lt;i class=&quot;success_icon&quot;&gt;&lt;/i&gt; 恭喜您输入正确&#39;;
   } else {
     // console.log(&#39;不正确&#39;);
     this.nextElementSibling.className = &#39;error&#39;;
     this.nextElementSibling.innerHTML = &#39;&lt;i class=&quot;error_icon&quot;&gt;&lt;/i&gt; 格式不正确,请从新输入 &#39;;
            }
        }
 };</code></pre>
<pre><code class="js">//密码验证:/^[a-zA-Z0-9_-]{6,16}$/
//再次输入密码只需匹配与上次输入的密码值 是否一致</code></pre>
<h3 id="正则替换replace"><a href="#正则替换replace" class="headerlink" title="正则替换replace"></a>正则替换replace</h3><p>replace() 方法可以实现替换字符串操作，用来替换的参数可以是一个字符串或是一个正则表达式。</p>
<p>正则表达式参数</p>
<pre><code>/表达式/[switch]</code></pre><p>switch（也称为修饰符）按照什么样的模式来匹配。有三种值</p>
<p>g: 全局匹配</p>
<p>i: 忽略大小写</p>
<p>gi: 全局匹配+忽略大小写</p>
<pre><code class="js">var str = &#39;andy和red&#39;;
var newStr = str.replace(&#39;andy&#39;, &#39;baby&#39;);
console.log(newStr)//baby和red
//等同于 此处的andy可以写在正则表达式内
var newStr2 = str.replace(/andy/, &#39;baby&#39;);
console.log(newStr2)//baby和red
//全部替换
var str = &#39;abcabc&#39;
var nStr = str.replace(/a/,&#39;哈哈&#39;)
console.log(nStr) //哈哈bcabc
//全部替换g
var nStr = str.replace(/a/g,&#39;哈哈&#39;)
console.log(nStr) //哈哈bc哈哈bc
//忽略大小写i
var str = &#39;aAbcAba&#39;;
var newStr = str.replace(/a/gi,&#39;哈哈&#39;)//&quot;哈哈哈哈bc哈哈b哈哈&quot;</code></pre>
<p><strong>案例:过滤敏感词汇</strong></p>
<pre><code class="js">&lt;textarea name=&quot;&quot; id=&quot;message&quot;&gt;&lt;/textarea&gt; &lt;button&gt;提交&lt;/button&gt;
&lt;div&gt;&lt;/div&gt;
&lt;script&gt;
    var text = document.querySelector(&#39;textarea&#39;);
    var btn = document.querySelector(&#39;button&#39;);
    var div = document.querySelector(&#39;div&#39;);
    btn.onclick = function() {
        div.innerHTML = text.value.replace(/激情|gay/g, &#39;**&#39;);
    }
&lt;/script&gt;</code></pre>
<h1 id="语法"><a href="#语法" class="headerlink" title="语法"></a>语法</h1><h2 id="目标"><a href="#目标" class="headerlink" title="目标"></a>目标</h2><ul>
<li>能够说出使用let关键字声明变量的特点</li>
<li>能够使用解构赋值从数组中提取值</li>
<li>能够说出箭头函数拥有的特性</li>
<li>能够使用剩余参数接收剩余的函数参数</li>
<li>能够使用拓展运算符拆分数组</li>
<li>能够说出模板字符串拥有的特性</li>
</ul>
<h2 id="ES6相关概念（★★）"><a href="#ES6相关概念（★★）" class="headerlink" title="ES6相关概念（★★）"></a>ES6相关概念（★★）</h2><h3 id="什么是ES6"><a href="#什么是ES6" class="headerlink" title="什么是ES6"></a>什么是ES6</h3><p>ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。</p>
<h3 id="为什么使用-ES6"><a href="#为什么使用-ES6" class="headerlink" title="为什么使用 ES6 ?"></a>为什么使用 ES6 ?</h3><p>每一次标准的诞生都意味着语言的完善，功能的加强。JavaScript语言本身也有一些令人不满意的地方。</p>
<ul>
<li>变量提升特性增加了程序运行时的不可预测性</li>
<li>语法过于松散，实现相同的功能，不同的人可能会写出不同的代码</li>
</ul>
<h2 id="ES6新增语法"><a href="#ES6新增语法" class="headerlink" title="ES6新增语法"></a>ES6新增语法</h2><h3 id="let（★★★）"><a href="#let（★★★）" class="headerlink" title="let（★★★）"></a>let（★★★）</h3><p>ES6中新增了用于声明变量的关键字</p>
<h4 id="let声明的变量只在所处于的块级有效"><a href="#let声明的变量只在所处于的块级有效" class="headerlink" title="let声明的变量只在所处于的块级有效"></a>let声明的变量只在所处于的块级有效</h4><pre><code class="javascript"> if (true) { 
     let a = 10;
 }
console.log(a) // a is not defined</code></pre>
<p><strong>注意：</strong>使用let关键字声明的变量才具有块级作用域，使用var声明的变量不具备块级作用域特性。</p>
<h4 id="不存在变量提升"><a href="#不存在变量提升" class="headerlink" title="不存在变量提升"></a>不存在变量提升</h4><pre><code class="javascript">console.log(a); // a is not defined 
let a = 20;</code></pre>
<h4 id="暂时性死区"><a href="#暂时性死区" class="headerlink" title="暂时性死区"></a>暂时性死区</h4><p>利用let声明的变量会绑定在这个块级作用域，不会受外界的影响</p>
<ul>
<li>变量要先声明后使用</li>
<li>建议使用let/const 而少使用var</li>
</ul>
<pre><code class="javascript">var tmp = 123;
if (true) { 
    tmp = &#39;abc&#39;;//tmp is not defined
    let tmp; 
} </code></pre>
<h4 id="经典面试题"><a href="#经典面试题" class="headerlink" title="经典面试题"></a>经典面试题</h4><pre><code class="javascript"> var arr = [];
 for (var i = 0; i &lt; 2; i++) {
     arr[i] = function () {
         console.log(i); 
     }
 }
 arr[0]();//2
 arr[1]();//2
</code></pre>
<p><img src="http://helloxx.cn/let%E9%9D%A2%E8%AF%95%E9%A2%98.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p><strong>经典面试题图解：</strong>此题的关键点在于变量i是全局的，函数执行时输出的都是全局作用域下的i值。</p>
<pre><code class="javascript"> let arr = [];
 for (let i = 0; i &lt; 2; i++) {
     arr[i] = function () {
         console.log(i); 
     }
 }
 arr[0]();//0
 arr[1]();//1
</code></pre>
<p><img src="http://helloxx.cn/let%E9%9D%A2%E8%AF%95%E9%A2%982.png" srcset="/myblog/img/loading.gif" alt=""></p>
<p><strong>经典面试题图解：</strong>此题的关键点在于每次循环都会产生一个块级作用域，每个块级作用域中的变量都是不同的，函数执行时输出的是自己上一级（循环产生的块级作用域）作用域下的i值.</p>
<h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><ul>
<li>let关键字就是用来声明变量的</li>
<li>使用let关键字声明的变量具有块级作用域， let声明后的变量不允许在同一作用域中重新声明 </li>
<li>在一个大括号中 使用let关键字声明的变量才具有块级作用域 var关键字是不具备这个特点的</li>
<li>防止循环变量变成全局变量</li>
<li>使用let关键字声明的变量没有变量提升</li>
<li>使用let关键字声明的变量具有暂时性死区特性</li>
</ul>
<h3 id="const（★★★）"><a href="#const（★★★）" class="headerlink" title="const（★★★）"></a>const（★★★）</h3><p>声明常量，常量就是值（内存地址）不能变化的量</p>
<h4 id="具有块级作用域"><a href="#具有块级作用域" class="headerlink" title="具有块级作用域"></a>具有块级作用域</h4><pre><code class="javascript"> if (true) { 
     const a = 10;
 }
console.log(a) // a is not defined</code></pre>
<h4 id="声明常量时必须赋值"><a href="#声明常量时必须赋值" class="headerlink" title="声明常量时必须赋值"></a>声明常量时必须赋值</h4><pre><code class="javascript">const PI; // Missing initializer in const declaration</code></pre>
<h4 id="常量赋值后，值不能修改-引用类型值可修改"><a href="#常量赋值后，值不能修改-引用类型值可修改" class="headerlink" title="常量赋值后，值不能修改(引用类型值可修改)"></a>常量赋值后，值不能修改(引用类型值可修改)</h4><pre><code class="javascript">const PI = 3.14;
PI = 100; // Assignment to constant variable.

const ary = [100, 200];
ary[0] = &#39;a&#39;;
ary[1] = &#39;b&#39;;
console.log(ary); // [&#39;a&#39;, &#39;b&#39;]; 
ary = [&#39;a&#39;, &#39;b&#39;]; // Assignment to constant variable.</code></pre>
<h4 id="小结-1"><a href="#小结-1" class="headerlink" title="小结"></a>小结</h4><ul>
<li>const声明的变量是一个常量</li>
<li>既然是常量不能重新进行赋值，如果是基本数据类型，不能更改值，如果是复杂数据类型，不能更改地址值</li>
<li>声明 const时候必须要给定值</li>
</ul>
<h3 id="let、const、var-的区别"><a href="#let、const、var-的区别" class="headerlink" title="let、const、var 的区别"></a>let、const、var 的区别</h3><ul>
<li>使用 var 声明的变量，其作用域为该语句所在的函数内，且存在变量提升现象</li>
<li>使用 let 声明的变量，其作用域为该语句所在的代码块内，不存在变量提升</li>
<li>使用 const 声明的是常量，在后面出现的代码中不能再修改该常量的值</li>
<li>let 全局声明的变量不存在于 window 对象中，这与 var 声明不同 </li>
</ul>
<table>
<thead>
<tr>
<th>var</th>
<th>let</th>
<th>const</th>
</tr>
</thead>
<tbody><tr>
<td>函数级作用域</td>
<td>块级作用域</td>
<td>块级作用域</td>
</tr>
<tr>
<td>变量提升</td>
<td>不存在变量提升</td>
<td>不存在变量提升</td>
</tr>
<tr>
<td>值可更改</td>
<td>值可更改</td>
<td>值不可更改</td>
</tr>
</tbody></table>
<h3 id="解构赋值（★★★）"><a href="#解构赋值（★★★）" class="headerlink" title="解构赋值（★★★）"></a>解构赋值（★★★）</h3><p>ES6中允许从数组中提取值，按照对应位置，对变量赋值，对象也可以实现解构</p>
<h4 id="数组解构"><a href="#数组解构" class="headerlink" title="数组解构"></a>数组解构</h4><pre><code class="javascript"> let [a, b, c] = [1, 2, 3];
 console.log(a)//1
 console.log(b)//2
 console.log(c)//3
//如果解构不成功，变量的值为undefined</code></pre>
<h4 id="对象解构"><a href="#对象解构" class="headerlink" title="对象解构"></a>对象解构</h4><pre><code class="javascript"> let person = { name: &#39;zhangsan&#39;, age: 20 }; 
 let { name, age } = person;
 console.log(name); // &#39;zhangsan&#39; 
 console.log(age); // 20

 let {name: myName, age: myAge} = person; // myName myAge 属于别名
 console.log(myName); // &#39;zhangsan&#39; 
 console.log(myAge); // 20
</code></pre>
<h4 id="小结-2"><a href="#小结-2" class="headerlink" title="小结"></a>小结</h4><ul>
<li>解构赋值就是把数据结构分解，然后给变量进行赋值</li>
<li>如果结构不成功，变量跟数值个数不匹配的时候，变量的值为undefined</li>
<li>数组解构用中括号包裹，多个变量用逗号隔开，对象解构用花括号包裹，多个变量用逗号隔开</li>
<li>利用解构赋值能够让我们方便的去取对象中的属性跟方法</li>
</ul>
<h3 id="箭头函数（★★★）"><a href="#箭头函数（★★★）" class="headerlink" title="箭头函数（★★★）"></a>箭头函数（★★★）</h3><p>ES6中新增的定义函数的方式。</p>
<pre><code class="javascript">() =&gt; {} //()：代表是函数； =&gt;：必须要的符号，指向哪一个代码块；{}：函数体
const fn = () =&gt; {}//代表把一个函数赋值给fn</code></pre>
<p>函数体中只有一句代码，且代码的执行结果就是返回值，可以省略大括号</p>
<pre><code class="javascript"> function sum(num1, num2) { 
     return num1 + num2; 
 }
 //es6写法
 const sum = (num1, num2) =&gt; num1 + num2; 
</code></pre>
<p>如果形参只有一个，可以省略小括号</p>
<pre><code class="javascript"> function fn (v) {
     return v;
 } 
//es6写法
 const fn = v =&gt; v;
</code></pre>
<p>箭头函数不绑定this关键字，箭头函数中的this，指向的是函数定义位置的上下文this</p>
<pre><code class="javascript">const obj = { name: &#39;张三&#39;} ;
function fn () { 
    console.log(this);//this 指向 是obj对象
    return () =&gt; { 
        console.log(this);//this 指向 的是箭头函数定义的位置，那么这个箭头函数定义在fn里面，而这个fn指向是的obj对象，所以这个this也指向是obj对象
    } 
} 
const resFn = fn.call(obj); 
resFn();
</code></pre>
<h4 id="小结-3"><a href="#小结-3" class="headerlink" title="小结"></a>小结</h4><ul>
<li>箭头函数中不绑定this，箭头函数中的this指向是它所定义的位置，可以简单理解成，定义箭头函数中的作用域的this指向谁，它就指向谁</li>
<li>箭头函数的优点在于解决了this执行环境所造成的一些问题。比如：解决了匿名函数this指向的问题（匿名函数的执行环境具有全局性），包括setTimeout和setInterval中使用this所造成的问题</li>
</ul>
<h4 id="面试题"><a href="#面试题" class="headerlink" title="面试题"></a>面试题</h4><pre><code class="javascript">var age = 100;

var obj = {
    age: 20,
    say: () =&gt; {
        alert(this.age)
    }
}

obj.say();//箭头函数this指向的是被声明的作用域里面，而对象没有作用域的，所以箭头函数虽然在对象中被定义，但是this指向的是全局作用域</code></pre>
<h3 id="剩余参数（★★）"><a href="#剩余参数（★★）" class="headerlink" title="剩余参数（★★）"></a>剩余参数（★★）</h3><p>剩余参数语法允许我们将一个不定数量的参数表示为一个数组，不定参数定义方式，这种方式很方便的去声明不知道参数情况下的一个函数</p>
<pre><code class="javascript">function sum (first, ...args) {
     console.log(first); // 10
     console.log(args); // [20, 30] 
 }
 sum(10, 20, 30)
</code></pre>
<h4 id="剩余参数和解构配合使用"><a href="#剩余参数和解构配合使用" class="headerlink" title="剩余参数和解构配合使用"></a>剩余参数和解构配合使用</h4><pre><code class="javascript">let students = [&#39;wangwu&#39;, &#39;zhangsan&#39;, &#39;lisi&#39;];
let [s1, ...s2] = students; 
console.log(s1);  // &#39;wangwu&#39; 
console.log(s2);  // [&#39;zhangsan&#39;, &#39;lisi&#39;]
</code></pre>
<h2 id="ES6-的内置对象扩展"><a href="#ES6-的内置对象扩展" class="headerlink" title="ES6 的内置对象扩展"></a>ES6 的内置对象扩展</h2><h3 id="Array-的扩展方法（★★）"><a href="#Array-的扩展方法（★★）" class="headerlink" title="Array 的扩展方法（★★）"></a>Array 的扩展方法（★★）</h3><h4 id="扩展运算符（展开语法）"><a href="#扩展运算符（展开语法）" class="headerlink" title="扩展运算符（展开语法）"></a>扩展运算符（展开语法）</h4><p>扩展运算符可以将数组或者对象转为用逗号分隔的参数序列</p>
<pre><code class="javascript"> let ary = [1, 2, 3];
 ...ary  // 1, 2, 3
 console.log(...ary);    // 1 2 3,相当于下面的代码
 console.log(1,2,3);</code></pre>
<h5 id="扩展运算符可以应用于合并数组"><a href="#扩展运算符可以应用于合并数组" class="headerlink" title="扩展运算符可以应用于合并数组"></a>扩展运算符可以应用于合并数组</h5><pre><code class="javascript">// 方法一 
 let ary1 = [1, 2, 3];
 let ary2 = [3, 4, 5];
 let ary3 = [...ary1, ...ary2];
 // 方法二 
 ary1.push(...ary2);</code></pre>
<h5 id="将类数组或可遍历对象转换为真正的数组"><a href="#将类数组或可遍历对象转换为真正的数组" class="headerlink" title="将类数组或可遍历对象转换为真正的数组"></a>将类数组或可遍历对象转换为真正的数组</h5><pre><code class="javascript">let oDivs = document.getElementsByTagName(&#39;div&#39;); 
oDivs = [...oDivs];</code></pre>
<h4 id="构造函数方法：Array-from"><a href="#构造函数方法：Array-from" class="headerlink" title="构造函数方法：Array.from()"></a>构造函数方法：Array.from()</h4><p>将伪数组或可遍历对象转换为真正的数组</p>
<pre><code class="javascript">//定义一个集合
let arrayLike = {
    &#39;0&#39;: &#39;a&#39;,
    &#39;1&#39;: &#39;b&#39;,
    &#39;2&#39;: &#39;c&#39;,
    length: 3
}; 
//转成数组
let arr2 = Array.from(arrayLike); // [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]</code></pre>
<p>方法还可以接受第二个参数，作用类似于数组的map方法，用来对每个元素进行处理，将处理后的值放入返回的数组</p>
<pre><code class="javascript"> let arrayLike = { 
     &quot;0&quot;: 1,
     &quot;1&quot;: 2,
     &quot;length&quot;: 2
 }
 let newAry = Array.from(arrayLike, item =&gt; item *2)//[2,4]
</code></pre>
<p>注意：如果是对象，那么属性需要写对应的索引</p>
<h4 id="实例方法：find"><a href="#实例方法：find" class="headerlink" title="实例方法：find()"></a>实例方法：find()</h4><p>用于找出第一个符合条件的数组成员，如果没有找到返回undefined</p>
<pre><code class="javascript">let ary = [{
     id: 1,
     name: &#39;张三&#39;
 }, { 
     id: 2,
     name: &#39;李四&#39;
 }]; 
 let target = ary.find((item, index) =&gt; item.id == 2);//找数组里面符合条件的值，当数组中元素id等于2的查找出来，注意，只会匹配第一个
</code></pre>
<h4 id="实例方法：findIndex"><a href="#实例方法：findIndex" class="headerlink" title="实例方法：findIndex()"></a>实例方法：findIndex()</h4><p>用于找出第一个符合条件的数组成员的位置，如果没有找到返回-1</p>
<pre><code class="javascript">let ary = [1, 5, 10, 15];
let index = ary.findIndex((value, index) =&gt; value &gt; 9); 
console.log(index); // 2</code></pre>
<h4 id="实例方法：includes"><a href="#实例方法：includes" class="headerlink" title="实例方法：includes()"></a>实例方法：includes()</h4><p>判断某个数组是否包含给定的值，返回布尔值。</p>
<pre><code class="javascript">[1, 2, 3].includes(2) // true 
[1, 2, 3].includes(4) // false
</code></pre>
<h3 id="String-的扩展方法"><a href="#String-的扩展方法" class="headerlink" title="String 的扩展方法"></a>String 的扩展方法</h3><h4 id="模板字符串（★★★）"><a href="#模板字符串（★★★）" class="headerlink" title="模板字符串（★★★）"></a>模板字符串（★★★）</h4><p>ES6新增的创建字符串的方式，使用反引号定义</p>
<pre><code class="javascript">let name = `zhangsan`;
</code></pre>
<h5 id="模板字符串中可以解析变量"><a href="#模板字符串中可以解析变量" class="headerlink" title="模板字符串中可以解析变量"></a>模板字符串中可以解析变量</h5><pre><code class="javascript">let name = &#39;张三&#39;; 
let sayHello = `hello,my name is ${name}`; // hello, my name is zhangsan</code></pre>
<h5 id="模板字符串中可以换行"><a href="#模板字符串中可以换行" class="headerlink" title="模板字符串中可以换行"></a>模板字符串中可以换行</h5><pre><code class="javascript"> let result = { 
     name: &#39;zhangsan&#39;, 
     age: 20,
     sex: &#39;男&#39; 
 } 
 let html = ` &lt;div&gt;
     &lt;span&gt;${result.name}&lt;/span&gt;
     &lt;span&gt;${result.age}&lt;/span&gt;
     &lt;span&gt;${result.sex}&lt;/span&gt;
 &lt;/div&gt; `;
</code></pre>
<h5 id="在模板字符串中可以调用函数"><a href="#在模板字符串中可以调用函数" class="headerlink" title="在模板字符串中可以调用函数"></a>在模板字符串中可以调用函数</h5><pre><code class="javascript">const sayHello = function () { 
    return &#39;哈哈哈哈 追不到我吧 我就是这么强大&#39;;
 }; 
 let greet = `${sayHello()} 哈哈哈哈`;
 console.log(greet); // 哈哈哈哈 追不到我吧 我就是这么强大 哈哈哈哈
</code></pre>
<h4 id="实例方法：startsWith-和-endsWith"><a href="#实例方法：startsWith-和-endsWith" class="headerlink" title="实例方法：startsWith() 和 endsWith()"></a>实例方法：startsWith() 和 endsWith()</h4><ul>
<li>startsWith()：表示参数字符串是否在原字符串的头部，返回布尔值</li>
<li>endsWith()：表示参数字符串是否在原字符串的尾部，返回布尔值</li>
</ul>
<pre><code class="javascript">let str = &#39;Hello world!&#39;;
str.startsWith(&#39;Hello&#39;) // true 
str.endsWith(&#39;!&#39;)       // true
</code></pre>
<h4 id="实例方法：repeat"><a href="#实例方法：repeat" class="headerlink" title="实例方法：repeat()"></a>实例方法：repeat()</h4><p>repeat方法表示将原字符串重复n次，返回一个新字符串</p>
<pre><code class="javascript">&#39;x&#39;.repeat(3)      // &quot;xxx&quot; 
&#39;hello&#39;.repeat(2)  // &quot;hellohello&quot;</code></pre>
<h3 id="Set-数据结构（★★）"><a href="#Set-数据结构（★★）" class="headerlink" title="Set 数据结构（★★）"></a>Set 数据结构（★★）</h3><p>ES6 提供了新的数据结构  Set。它类似于数组，但是成员的值都是唯一的，没有重复的值。</p>
<p>Set本身是一个构造函数，用来生成  Set  数据结构</p>
<pre><code class="javascript">const s = new Set();</code></pre>
<p>Set函数可以接受一个数组作为参数，用来初始化。</p>
<pre><code class="javascript">const set = new Set([1, 2, 3, 4, 4]);//{1, 2, 3, 4}
</code></pre>
<h4 id="实例方法"><a href="#实例方法" class="headerlink" title="实例方法"></a>实例方法</h4><ul>
<li>add(value)：添加某个值，返回 Set 结构本身</li>
<li>delete(value)：删除某个值，返回一个布尔值，表示删除是否成功</li>
<li>has(value)：返回一个布尔值，表示该值是否为 Set 的成员</li>
<li>clear()：清除所有成员，没有返回值</li>
</ul>
<pre><code class="javascript"> const s = new Set();
 s.add(1).add(2).add(3); // 向 set 结构中添加值 
 s.delete(2)             // 删除 set 结构中的2值   
 s.has(1)                // 表示 set 结构中是否有1这个值 返回布尔值 
 s.clear()               // 清除 set 结构中的所有值
 //注意：删除的是元素的值，不是代表的索引</code></pre>
<h4 id="遍历"><a href="#遍历" class="headerlink" title="遍历"></a>遍历</h4><p>Set 结构的实例与数组一样，也拥有forEach方法，用于对每个成员执行某种操作，没有返回值。</p>
<pre><code class="javascript">s.forEach(value =&gt; console.log(value))
</code></pre>

            </div>
            <hr>
            <div>
              <p>
                
                
              </p>
              
                <p class="note note-warning">本博客所有文章除特别声明外，均采用 <a href="https://zh.wikipedia.org/wiki/Wikipedia:CC_BY-SA_3.0%E5%8D%8F%E8%AE%AE%E6%96%87%E6%9C%AC" target="_blank" rel="nofollow noopener noopener">CC BY-SA 3.0协议</a> 。转载请注明出处！</p>
              
              
                <div class="post-prevnext row">
                  <div class="post-prev col-6">
                    
                    
                      <a href="/myblog/2019/05/05/Vue%E7%AC%94%E8%AE%B0/">
                        <i class="fa fa-chevron-left"></i>
                        <span class="hidden-mobile">Vue学习笔记</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </div>
                  <div class="post-next col-6">
                    
                    
                      <a href="/myblog/2019/03/15/JS%20DOM%20BOM%20%E6%93%8D%E4%BD%9C/">
                        <span class="hidden-mobile">JS DOM BOM操作</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="fa fa-chevron-right"></i>
                      </a>
                    
                  </div>
                </div>
              
            </div>

              
          </div>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc-start"></div>
<div id="toc">
  <p class="h5"><i class="far fa-list-alt"></i>&nbsp;目录</p>
  <div id="tocbot"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    
  </main>

  
    <a class="z-depth-1" id="scroll-top-button" href="#" role="button">
      <i class="fa fa-chevron-up scroll-top-arrow" aria-hidden="true"></i>
    </a>
  

  
    <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
  

  

  

  <footer class="mt-5">
  <div class="text-center py-3">
    <div>
      <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><b>Hexo</b></a>
      <i class="iconfont icon-love"></i>
      <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"> <b>Fluid</b></a>
    </div>
    

    

    
  </div>
</footer>

<!-- SCRIPTS -->
<script  src="https://cdn.staticfile.org/jquery/3.4.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/popper.js/1.16.1/umd/popper.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.4.1/js/bootstrap.min.js" ></script>
<script  src="https://cdn.staticfile.org/mdbootstrap/4.13.0/js/mdb.min.js" ></script>
<script  src="/myblog/js/main.js" ></script>


  <script  src="/myblog/js/lazyload.js" ></script>



  
  <script  src="https://cdn.staticfile.org/tocbot/4.10.0/tocbot.min.js" ></script>
  <script>
    $(document).ready(function () {
      var navHeight = $('#navbar').height();
      var toc = $('#toc');
      var boardCtn = $('#board-ctn');
      var boardTop = boardCtn.offset().top;
      var tocLimMax = 2 * boardTop + boardCtn.height();

      $(window).scroll(function () {
        var tocLimMin = $('#toc-start').offset().top - navHeight;
        var scroH = document.body.scrollTop + document.documentElement.scrollTop;

        if (tocLimMin <= scroH && scroH <= tocLimMax) {
          toc.css({
            'display': 'block',
            'position': 'fixed',
            'top': navHeight,
          });
        } else if (scroH <= tocLimMin) {
          toc.css({
            'position': '',
            'top': '',
          });
        } else if (scroH > tocLimMax) {
          toc.css('display', 'none');
        }
      });
      tocbot.init({
        tocSelector: '#tocbot',
        contentSelector: '.post-content',
        headingSelector: 'h1,h2,h3,h4,h5,h6',
        linkClass: 'tocbot-link',
        activeLinkClass: 'tocbot-active-link',
        listClass: 'tocbot-list',
        isCollapsedClass: 'tocbot-is-collapsed',
        collapsibleClass: 'tocbot-is-collapsible',
        scrollSmooth: true,
        headingsOffset: -boardTop
      });
      if ($('.toc-list-item').length > 0) {
        $('#toc > p').css('visibility', 'visible');
      }
      var offset = boardCtn.css('margin-right')
      $('#toc-ctn').css({
        'right': offset
      })
    });
  </script>





  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>
  <script  src="/myblog/js/clipboard-use.js" ></script>








<!-- Plugins -->



  <script  src="https://cdn.staticfile.org/prettify/188.0.0/prettify.min.js" ></script>
  <script>
    $(document).ready(function () {
      $('pre').addClass('prettyprint  linenums');
      prettyPrint();
    })
  </script>



  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
  <script>
    var typed = new Typed('#subtitle', {
      strings: [
        '  ',
        "JavaScript高级&ES6 学习笔记&nbsp;",
      ],
      cursorChar: "_",
      typeSpeed: 70,
      loop: false,
    });
    typed.stop();
    $(document).ready(function () {
      $(".typed-cursor").addClass("h2");
      typed.start();
    });
  </script>



  <script  src="https://cdn.staticfile.org/anchor-js/4.2.2/anchor.min.js" ></script>
  <script>
    anchors.options = {
      placement: "right",
      visible: "hover",
      
    };
    var el = "h1,h2,h3,h4,h5,h6".split(",");
    var res = [];
    for (item of el) {
      res.push(".markdown-body > " + item)
    }
    anchors.add(res.join(", "))
  </script>



  <script  src="/myblog/js/local-search.js" ></script>
  <script>
    var path = "/myblog/local-search.xml";
    var inputArea = document.querySelector("#local-search-input");
    inputArea.onclick = function () {
      getSearchFile(path);
      this.onclick = null
    }
  </script>



  <script defer src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>
  <script>
    $("#post img:not(.no-zoom img, img[no-zoom])").each(
      function () {
        var element = document.createElement("a");
        $(element).attr("data-fancybox", "images");
        $(element).attr("href", $(this).attr("src"));
        $(this).wrap(element);
      }
    );
  </script>












</body>
</html>
